Suggestion: use option ‘hide all code’ in the menu at top-right, then expand code chunks when interested.
Note: Time consuming computations have been #-commented out for convenience, after data were saved


Introduction

Spiders are an incredibly diverse order of arthropods that play vital roles in diverse ecosystems, particularly as key predators that modulate biomass on a global scale (Nyffeler and Birkhofer 2017). There are currently 48,789 species described in the World spider catalog (https://wsc.nmbe.ch/) and novel species are being added on a regular basis. Differentiation of such a large number of species based on morphology alone is tremendously challenging. This difficulty is compounded by other inconvenient characteristics of spiders including sexual dimorphism, developmental changes in morphology, and their cryptic lifestyles (Tyagi et al. 2019).

As morphological classification of large numbers of spiders is generally tedious and impractical, DNA barcoding has become routine method for species identification in ecological studies (Tahir et al. 2019). The characteristics of the mitochondrial cytochrome c oxidase subunit 1 (CO1) gene make it an ideal marker for differentiating species (Ratnasingham and Hebert 2007, 2013). In a relatively limited time, a large amount of barcode sequences have been accumulated in the Barcode of Life Database, making it a useful resource for ecology research.

Spider diversity generally decreases with distance from the equator (Piel 2018). There is some debate as to whether the distribution is even between hemispheres or pear-shaped with the southern hemisphere being more diverse. In this work, I examined whether the collection of DNA-barcoded spider specimens in the BOLD database shows the diversity trend across latitudes as is reported in the literature. Additionally, sampling depth and geographic bias of the BOLD data were evaluated.


Analysis and Results

Software/Libraries

This work was produced with the R language and the following packages:

# packages used
library(bold)
library(tidyverse)
library(ggthemes)
library(vegan)
library(patchwork)
library(leaflet)
library(gt)
library(kableExtra)
library(ggrepel)
library(scales)
library(rcartocolor)
library(igraph)
library(plotly)



Downloading BOLD specimen records

All specimen records for Araneae were downloaded from the BOLD api on 2020-09-29. I also obtained the World spider catalog dataset (on the same date) as a reference for comparison of taxonomic identifiers.

## build the url for downloading
# taxon <- "Araneae"
# taxon <- paste0("taxon=", taxon)
# prefix <- "http://www.boldsystems.org/index.php/API_Public/specimen?"
# fmt <- "&format=tsv"
# url <- paste0(prefix, taxon, fmt)
# 
# # download, parse data
# Araneae.df <- read_delim(url, delim = '\t',guess_max = 10000)
# write_rds(Araneae.df, "./data/BOLD.araneae.rds")
# 

BOLD ‘Aranaea’ dataset

The dataset used in this analysis contained all the available specimen records of the order Araceae. Any records lacking BIN identifiers or geographic metadata were removed. There are 95,479 specimen records in this selection, representing 9,757 BIN clusters and these were collected in 136 countries. Specimen records were grouped by absolute latitude and classified as tropical (0-20˚), sub-tropical (20-40˚), temperate (40-60˚), or extreme (60-90˚). Similarly, countries were grouped by their mean latitude of all specimens for diversity analyses.

Table 1. Summary of Araneae specimen records from the BOLD database that were used in this analysis.

kable(data_summary, format = 'pipe',escape = TRUE)
Characteristic Value
Specimen records in BOLD 124,682
Records selection (not missing BIN and country data) 95,910
Number of unique BINs in selected records 9,845
Unique family taxa 113
Unique genus taxa 1,122
Unique species taxa 3,822
Source countries in selected records 136
Latitude range -55.6 : 82.5

Specimen Map

A map showing the geographic distribution of spider specimens in the BOLD database. Strong North American and European sampling bias is evident; the Southern hemisphere is not well represented, especially Africa and Central Asia.

## group specimens on a 1deg grid
spider.map.df <- Araneae.df %>%
  # round coords to nearest deg.
  mutate(lat = round(lat),
         lon = round(lon)) %>%
  # group/count all specimens with same coords
  group_by(lat, lon) %>%
  mutate(n=n(),
         BINs = length(unique(bin_uri))) %>%
  select(lat, lon, n, BINs) %>%
  distinct() %>%
  # create popup labels with info
  mutate(popups = paste0(
    "<b>Lat: </b>", lat,
    '<br><b>Long: </b>', lon,
    "<br><b>Specimens: </b>", n,
    "<br><b>BINs: </b>", BINs),
    labs = paste(n, 'specimens')
    ) %>%
  filter(!(is.na(lat)|is.na(lon)))


# create map

make.spider.map <- function(spider.map.df){
  
  spider.map <- leaflet(spider.map.df) %>%
    setView(zoom=1, lat=30, lng=5) %>%
    addProviderTiles(providers$CartoDB.Positron) 
  
  # add latitude lines that samples were grouped by
  for (i in c(-60, -40, -20, 0, 20, 40, 60)) {
    spider.map <- spider.map %>%
      addPolylines(lng = c(-360:360, 360:-360), 
                   lat = rep(i, times=720), weight = 0.4)
  }
  
  spider.map <- spider.map %>%
    addCircleMarkers(
      color = '#f20000',
      lng = ~lon,
      lat = ~lat,
      radius = ~(log(n)+1)*0.4,
      fillOpacity = 0.3,
      stroke = FALSE,
      popup = ~popups,
      label = ~labs
    )  
  return(spider.map)
}

make.spider.map(spider.map.df)

Figure 1. Geography of BOLD spider specimens. Markers show the location and amount of specimens collected at each location; specimens were binned into a 1deg x 1deg grid for counting. Latitude lines correspond to the zones that were considered in the geographic analysis of spider diversity. (An interactive version with zoom & labels is presented in the accompanying html-notebook ‘JMogg_spider_diversity_notebook.html’)

Composition and sampling depth by latitude

# tablulate specimen records count by BIN
bin.table <- Araneae.df %>%
  count(bin_uri)

# plot histogram of specimen counts for BINs (bin size distribution)

bin.hist <- bin.table %>%
  ggplot(aes(x = n)) +
  geom_histogram(bins = 100) +
  scale_x_log10() + scale_y_log10() +
  scale_fill_viridis_d() +
  labs(x = 'Specimens assigned to BIN',
       y = 'Frequency') +
  theme_classic()
  
# Araneae.df2 <- Araneae.df %>%
#   mutate(plotly.labs = paste("<b>Lat:</b>", lat,
#                              '<br><b>Family</b>:, family_name))
# Specimen distribution by latitude
spec.lats.bar <- ggplot(Araneae.df, aes(y=lat, fill = family_name)) +
  geom_histogram(alpha = 0.8, colour = 'lightgrey', orientation = 'y',
                 show.legend = FALSE) +
  scale_fill_viridis_d(option = 'C') +
  labs(y = 'Latitude', x = 'Specimen count') +
  theme_classic() +
  theme(legend.position = 'null')

# show both plots

ggplotly(spec.lats.bar)

Figure 2a. A plot showing the number of samples collected by latitude; colors correspond to different spider families; popup labels show family name and specimen count - please ignore latitude in popup labels and read from y-axis. Families can be hidden/revealed by clicking icons on the legend (scroll to browse).

bin.hist

Figure 2b. A histogram showing the distribution of the number of specimens that have been assigned to each BIN.


Community abundances & alpha-diversity analysis

Community abundance tables were created for the entire dataset, by country and by latitude zone for diversity analyses with the vegan package.

# # creating community abundance matrices for vegan functions
# # Make tables with bins as columns + replace missing values with zeroes
# 
# # Bin counts from full dataset
# Araneae.df.bins <- Araneae.df %>%
#   # count specimens
#   count(bin_uri) %>%
#   # make wide table
#   pivot_wider(names_from = bin_uri, values_from = n)
# write_rds(Araneae.df.bins, "./data/Araneae.bins.rds")
# 
# # community matrix with countries as observations 
# # must make site into rownames
# Araneae.country.bins <- Araneae.df %>%
#   count(bin_uri, country) %>%
#   pivot_wider(names_from = bin_uri, values_from = n) %>%
#   # replace NA with 0 values
#   mutate(across(where(is.numeric), ~replace_na(.x, 0)))  %>%
#   # make site labels into df rownames
#   remove_rownames %>%
#   column_to_rownames(var = "country")
# write_rds(Araneae.country.bins, "./data/Araneae.country.bins.rds")
# 
# # community matrix with latitude zones as observations
# Araneae.zone.bins <- Araneae.df %>%
#   count(bin_uri, zone) %>%
#   pivot_wider(names_from = bin_uri, values_from = n) %>%
#   mutate(across(where(is.numeric), ~replace_na(.x, 0))) %>%
#   filter(!is.na(zone)) %>%
#   remove_rownames %>%
#   column_to_rownames(var = "zone")
# write_rds(Araneae.zone.bins, "./data/Araneae.zone.bins.rds")

Richness of BINs and rarefied richness (sample=500), Shannon diversity, and Simpson diversity were calculated for each country and each latitude zones.

# community abundance matrices made in previous code chunk
Araneae.bins <- read_rds("./data/Araneae.bins.rds")
Araneae.zone.bins <- read_rds("./data/Araneae.zone.bins.rds")
Araneae.country.bins <- read_rds("./data/Araneae.country.bins.rds")

country.bins.500 <- Araneae.country.bins %>%
  bind_cols(sum = rowSums(Araneae.country.bins)) %>%
  filter(sum > 500) %>%
  select(-sum)

# calculate richness & alpha diversity metrics for each country
alpha.diversity.country <- data.frame(Country=rownames(country.bins.500)) %>%
  bind_cols(
    list(
      Specimens = rowSums(country.bins.500),
      Richness = rowSums(country.bins.500 > 0),
      `Rarefied` = vegan::rarefy(country.bins.500, sample = 500),
      Shannon = vegan::diversity(country.bins.500, index = 'shannon'),
      Simpson = vegan::diversity(country.bins.500, index = 'simpson')
    )
    ) %>%
  # round numbers off to 2 decimals
  mutate(Shannon = round(Shannon, 2),
         Simpson = round(Simpson, 2)) %>%
  arrange(desc(Specimens)) %>%
  left_join(country_zones %>% select(-country), by = 'Country')

# kable(alpha.diversity.country, format = 'simple')

rich_species_lm <- ggplot(alpha.diversity.country, 
                          aes(x=log(Specimens), 
                              y = log(Richness))) +
  geom_smooth(method = lm) +
  geom_point(aes(color = zone)) +
  ggrepel::geom_text_repel(aes(label = Country, color = zone)) +
  scale_color_discrete("Lat. zone") +
  theme_classic()
# rich_species_lm

##########

# arranging labels for plot below (lexico sort y-axis countries)    
alpha.diversity.country$Country <- factor(alpha.diversity.country$Country, levels=rev(sort(alpha.diversity.country$Country)))

# arranging data to long form with diversity indice + value rows for ea country
alpha.country.long <- alpha.diversity.country %>%
  pivot_longer(Rarefied:Simpson) %>%
  arrange(desc(Country)) 

# rearrange grid columns for plot by changing levels
alpha.country.long$name <- factor(alpha.country.long$name, levels = c("Richness", "Rarefied","Shannon", "Simpson"))
alpha.country.long$zone <- factor(alpha.country.long$zone, levels = c("Extreme", "Temperate","Sub-tropical", "Tropical"))

# grid plot of diversity indices
diversity.plot <- ggplot(alpha.country.long,
                         aes(y = Country, x = value, colour = zone)) +
  geom_point() +
  geom_segment(aes(x = 0, xend = value, yend = Country)) +
  facet_grid(~name, scales = 'free') +
  labs(x = '', y='') +
  scale_color_discrete("Lat. zone") +
  scale_fill_discrete("Lat. zone") +
  theme_classic() +
  theme(strip.background = element_blank(),
        legend.position = 'null',
        axis.text.x = element_text(angle = 30, vjust = 0))

########

# calculate richness & alpha diversity metrics for latitude zones
alpha.diversity.zones <- data.frame(Zone=rownames(Araneae.zone.bins)) %>%
  # bind a new column for each statistic
  bind_cols(
    list(
      `Range (abs. deg)` = rev(c('0-20', '20-40','40-60', '60+')),
      n = rowSums(Araneae.zone.bins),
      Richness = rowSums(Araneae.zone.bins > 0),
      `Rarefied` = vegan::rarefy(Araneae.zone.bins, sample = 500),
      Shannon = vegan::diversity(Araneae.zone.bins, index = 'shannon'),
      Simpson = vegan::diversity(Araneae.zone.bins, index = 'simpson')
    )
  ) %>%
  mutate(Shannon = round(Shannon, 2),
         Simpson = round(Simpson, 2),
         `Rarefied` = round(`Rarefied`))

#######

# arranging labels for plot below (lexico sort y-axis zones)    
alpha.diversity.zones$Zone <- factor(alpha.diversity.zones$Zone, levels=rev(sort(alpha.diversity.zones$Zone)))

# arranging data to long form with diversity indice + value rows for ea country
alpha.zones.long <- alpha.diversity.zones %>%
  pivot_longer(Rarefied:Simpson) %>%
  arrange(desc(Zone)) 

# rearrange grid rows, columns for plot
alpha.zones.long$Zone <- factor(alpha.zones.long$Zone, levels = c("Extreme", "Temperate","Sub-tropical", "Tropical"))

alpha.zones.long$name <- factor(alpha.zones.long$name, levels = c("Richness", "Rarefied","Shannon", "Simpson"))


# grid plot of diversity indices
diversity.plot.zone <- ggplot(alpha.zones.long,aes(y = Zone, x = value, fill = Zone)) +
  geom_col() +
  # geom_segment(aes(x = 0, xend = value, yend = Zone)) +
  facet_grid(~name, scales = 'free') +
  labs(x = '', y='') +
  scale_fill_discrete("Lat. zone") +
  theme_classic() +
  
  theme(strip.background = element_blank(),
        legend.position = 'null')

#########

alpha.zones.countries.plot <- alpha.country.long %>%
  ggplot(aes(y=zone, x = value, colour = zone)) +
  geom_boxplot(colour = 'gray80',outlier.shape = NA) +
  geom_jitter(alpha = 0.9, pch = 0) +
  scale_fill_discrete("Lat. zone") +
  geom_point(data = alpha.zones.long, aes(y=Zone, x = value, colour = Zone), size = 2) +
  facet_grid(~name, scales='free') +
  scale_color_discrete("Lat. zone") +
  scale_fill_discrete("Lat. zone") +
  labs(x='', y='') +
  theme_classic() +
  theme(strip.background = element_blank(),
        legend.position = 'null',
        axis.text.x = element_text(angle = 30, vjust = 0))

Table 2. Richness and diversity of the BOLD spider collection in different latitude zones (based on absolute distance from the equator).

kable(alpha.diversity.zones, format = 'pipe')
Zone Range (abs. deg) n Richness Rarefied Shannon Simpson
Extreme 60+ 7439 843 262 5.83 0.99
Temperate 40-60 55897 2963 318 6.61 1.00
Sub-tropical 20-40 17126 3470 377 7.20 1.00
Tropical 0-20 6346 1960 370 6.89 1.00

patchwork::wrap_plots(alpha.zones.countries.plot/diversity.plot)

Figure 4. Rarefied richness (n=500), Shannon diversity, and Simpson diversity of spider spider communities in latitude zones (top) and countries (bottom). Countries were assigned to zones based on their mean specimen latitude. top: In each panel, the values for each country in the zone are shown as hollow squares, with the distribution shown by the boxplot; the values for the zone communities shown as solid circles. bottom: the index value is shown for each country, lollipops are colored by the latitude zone the country was assigned to.

Rarefaction & Species Abundance Curves

Rarefaction were computed using the vegan::rarecurve function for specimens grouped by each of country and latitude zone.

# # full data rarefaction
# Araneae.rar <- rarecurve(Araneae.df.bins,)
# Araneae.rar <- tibble(y = Araneae.rar[[1]]) %>%
#   mutate(x=row_number())
# write_rds(Araneae.rar, "./data/Araneae.rarefaction.rds")
# 
# ## rarefaction curves by lat zone
# Araneae.zone.rar <- rarecurve(Araneae.zone.bins)
# 
# # manipulate list output from vegan back into tidy data
# Araneae.zone.rar <- tibble(zone = rownames(Araneae.zone.bins),
#        list = Araneae.zone.rar) %>%
#   # spread list into individual columns
#   unnest_wider(col = list) %>%
#   # get long form table
#   pivot_longer(cols = -zone) %>%
#   # remove rows missing value & useless names column
#   filter(!is.na(value)) %>%
#   select(-name) %>%
#   # create vector for sampling depth
#   group_by(zone) %>%
#   mutate(sample_size = row_number())
# write_rds(Araneae.zone.rar, "./data/Araneae.zones.rarefaction.rds")
# 
# ## rarefaction curves by country
# Araneae.country.rar <- rarecurve(Araneae.country.bins)
# 
# # manipulate list output from vegan back into tidy data
# Araneae.country.rar <- tibble(Country = rownames(Araneae.country.bins),
#        list = Araneae.country.rar) %>%
#   unnest_wider(col = list) %>%
#   pivot_longer(cols = -Country) %>%
#   filter(!is.na(value)) %>%
#   select(-name) %>%
#   group_by(Country) %>%
#   mutate(sample_size = row_number())
# write_rds(Araneae.country.rar, "./data/Araneae.country.rarefaction.rds")

Species accumulation curves were computed using the vegan::specaccum function for specimens grouped by each of country and latitude zone.

# ## Species accumulation curves
# # specaccum by country
# Specaccum.country <- specaccum(Araneae.country.bins)
# Specaccum.country <- tibble(
#   sites = Specaccum.country['sites'],
#   richness = Specaccum.country['richness'],
#   sd = Specaccum.country['sd'],
#   ) %>%
#   unnest(cols = c(sites, richness, sd)) %>%
#   mutate(sd1 = ifelse(richness-sd>=0, richness-sd, 0),
#          sd2 = richness+sd)
# write_rds(Specaccum.country, "Specaccum.country.rds")
# 
# # specaccum by zone
# Specaccum.zone <- specaccum(Araneae.zone.bins)
# Specaccum.zone <- tibble(
#   sites = Specaccum.zone['sites'],
#   richness = Specaccum.zone['richness'],
#   sd = Specaccum.zone['sd'],
#   ) %>%
#   unnest(cols = c(sites, richness, sd)) %>%
#   mutate(sd1 = ifelse(richness-sd>=0, richness-sd, 0),
#          sd2 = richness+sd)
# write_rds(Specaccum.zone, "./data/Specaccum.zone.rds")

Plots were created for the rarefaction and species accumulation curves in the following code:

## RAREFACTION
# read in rar. curve data computed above
Araneae.rar <- read_rds("./data/Araneae.rarefaction.rds")
Araneae.zone.rar <- read_rds("./data/Araneae.zones.rarefaction.rds")
Araneae.country.rar <- read_rds("./data/Araneae.country.rarefaction.rds")

# rarefaction plot for entire dataset
plot.rar.full <- Araneae.rar %>%
  ggplot(aes(x=x/1000, y=y)) +
  geom_line() +
  labs(y = 'Unique BINs', x = 'Sample size (k)') +
  theme_classic()

# rarefaction curves for latitude zones
plot.rar.zone <- ggplot(Araneae.zone.rar,
                        aes(x=sample_size/1000, y = value,
                            group = zone, colour = zone)) +
  geom_line(alpha = 0.7) +
  scale_colour_discrete('Lat. zone') +
  labs(x = 'Sample size (k)', y = 'Unique BINs') +
  theme_classic()

# added lat zone labels to country rarefaction curves data for plot
Araneae.country.rar <- left_join(Araneae.country.rar, country_zones, by = 'Country')

# plot rarefaction curves for each country, colour by zone
plot.rar.country <-
  Araneae.country.rar %>%
  filter(!is.na(zone)) %>%
  ggplot(aes(x=sample_size/1000, y = value)) +
  geom_line(aes(group = Country, colour = zone), alpha = 0.7) +
  # add labels for 10 most-sampled countries
  geom_text_repel(data = country.specimens.table[1:10,],
                   aes(label = country, x = specimens/1000, y = species),
                   nudge_x = 0, size = 3,
                   na.rm = TRUE) +
  scale_colour_discrete('Lat. zone') +
  labs(x = 'Sample size (k)', y = 'Unique BINs') +
  theme_classic()

plot.rar.country2 <- 
  Araneae.country.rar %>%
  filter(!is.na(zone)) %>%
  ggplot(aes(x=sample_size, y = value)) +
  geom_line(aes(group = Country, colour = zone), alpha = 0.7) +
  # add labels for 10 most-sampled countries
  geom_text_repel(data = country.specimens.table[1:10,],
                   aes(label = country, x = specimens, y = species),
                   nudge_x = 0, size = 3,
                   na.rm = TRUE) +
  scale_colour_discrete('Lat. zone') +
  labs(x = 'Sample size', y = 'Unique BINs') +
  theme_classic() +
  xlim(c(0, 500)) +
  ylim(c(0, 340))


## SPECIES ACCUMULATION
Specaccum.country <- read_rds("./data/Specaccum.country.rds")
Specaccum.zone <- read_rds("./data/Specaccum.zone.rds")

# plot species accumulation by country
plot.Specaccum.country <-  ggplot(Specaccum.country) +
  geom_ribbon(aes(x=sites, y=richness, ymin = sd1, ymax = sd2),
              fill = 'cornflowerblue', alpha = 0.3) +
  geom_line(aes(x = sites, y = richness),
            size = 1.3, colour = 'blue4', alpha = 0.7) +
  labs(y = 'BIN Richness', x = 'Countries') +
  theme_classic()

# plot species accumulation by latitude zone
plot.Specaccum.zone <-  ggplot(Specaccum.zone) +
  geom_ribbon(aes(x=sites, y=richness, ymin = sd1, ymax = sd2),
              fill = 'red', alpha = 0.2) +
  geom_line(aes(x = sites, y = richness),
            size = 1.3, colour = 'red3', alpha = 0.7) +
  labs(y = 'BIN Richness', x = 'Latitude zones') +
  theme_classic()

## create rarefaction/specaccum plots figure
# show rarefaction plots panel with patchwork::
(plot.rar.full + plot.rar.zone) / 
  (plot.rar.country + plot.rar.country2) /
  (plot.Specaccum.country + plot.Specaccum.zone) +
  plot_annotation(tag_levels = 'A') +
  plot_layout(guides = 'collect') & 
  theme(plot.tag.position = c(0, 1),
        legend.position = "right",
        plot.tag = element_text(size = 8, hjust = 0, vjust = 0))

Figure 3. A-D: Rarefaction curves for entire collection of BOLD spider specimens (A), by latitude zone (B), and by source country (C). Because of the discrepency in sampling, a close-up of the countries’ rarefaction curves are shown for smaller sample sizes (D). Curves are coloured by latitude zone where applicable. Countries are assigned to latitude zones by the mean latitude of all their samples. Rarefaction curves were computed using the vegan::rarecurve function. EF: Species accumulation curves were computed using the vegan::specaccum function for specimens grouped by each of country (E) and latitude zone (F); lines show richness +/- sd.

Ordination by NMDS and species network anaylsis

# NMDS
zone.nmds <- metaMDS(Araneae.zone.bins, distance = 'bray', trace = FALSE)
# zone.nmds
par(mar=c(5,4,1,1))
plot(zone.nmds, alpha=0.5, cex = 0.7)
text(zone.nmds, display = 'sites', cex = 0.9)

Figure 5. NMDS of spider BIN abundances in four latitude zones using Bray distance and Wisconsin standardization of square-root-transformed abundances.

## Network plot with shared BINs between zones
Araneae.zone.bins <- read_rds("./data/Araneae.zone.bins.rds")
# make an edgelist for simple graph (for bins shared between zones)
edgelist <- tibble(
  u = c(rownames(Araneae.zone.bins)),
  v = rep(list(rownames(Araneae.zone.bins)),4)
) %>%
  unnest(v) %>%
  filter(!u==v)


# get rid of duplicate edges in edgelist (since graph is not directional)
edge.strings <-  str_split(paste(edgelist$u, edgelist$v), ' ')
# sort edges to remove directionality
edgelist <- unique(lapply(edge.strings, function(x) unique(sort(x))))
# remove self-self edges
edgelist <- edgelist[which(lengths(edgelist)>1)]
# paste u v vertices for each edge to filter bins.edgelist later (below)
edgelist <- lapply(edgelist, function(x) paste0(x, collapse = ' '))
rm(edge.strings)

# Get list of unique bins for each zone from zone abund. matrix
zone.bins.list <- tibble(Araneae.zone.bins) %>%
  mutate(zone = rownames(Araneae.zone.bins)) %>%
  pivot_longer(-zone) %>%
  filter(!value == 0) %>%
  group_by(zone) %>%
  mutate(bins = list(name)) %>%
  select(-c(value, name)) %>%
  distinct() %>%
  mutate(uniques = unique(bins)) 


# Create matrix with sizes of intersect of unique bins between zones. Each col has the size of the intersection between a zone and each zone (self-self is on diagonal) - for network edge weights
bins.ls <- zone.bins.list %>%
  select(zone, bins) %>%
  mutate(Extreme = length(intersect(zone.bins.list[1, 3][[1]][[1]], bins[[1]])),
         Temperate = length(intersect(zone.bins.list[2, 3][[1]][[1]], bins[[1]])),
         `Sub-tropical` = length(intersect(zone.bins.list[3, 3][[1]][[1]], bins[[1]])),
         Tropical = length(intersect(zone.bins.list[4, 3][[1]][[1]], bins[[1]])),
  ) %>%
  select(-bins) %>%
  pivot_longer(Extreme:Tropical) %>%
  rename(zone1 = zone,
         zone2 = name,
         weight = value)

# Filter weighted edgelist to keep single edge for each pair (not bidirectional - made 'edgelist' at top of chunk)
bins.edges <- bins.ls %>%
  filter(!zone1 == zone2) %>%
  mutate(edge = paste(zone1, zone2)) %>%
  filter(edge %in% edgelist) %>%
  select(-edge)


# total number of unique bins at each zone - for vertex size
total_bins <- bins.ls  %>%
  filter(zone1 == zone2) %>%
  select(-zone2) %>%
  rename(size = weight)

net <- graph_from_data_frame(d= bins.edges, vertices = total_bins, directed = F)

#vertice properties
V(net)$color <- c( 'cyan', "gold", "tomato", "plum")
V(net)$size <- total_bins$size/100 + 20

# edge properties
E(net)$weight <- bins.edges$weight*100
E(net)$width <- sqrt(E(net)$weight)/20
E(net)$edge.label <- bins.edges$weight
E(net)$edge.color <- "gray90"
E(net)$arrow.size <- .0

# Plot species network
set.seed(4)
par(mar=c(1,1,1,1))
plot(net, 
     layout = layout.fruchterman.reingold(net),
     label.dist = 2,
     edge.label = bins.edges$weight,
     edge.label.color ="navy",
     edge.label.cex = 0.8,
     edge.label.family = 'sans',
     vertex.label = paste0(V(net)$name, '\n(', total_bins$size, ')'),
     vertex.label.color="black",
     vertex.label.family = 'sans',
     vertex.label.font = 2,
     vertex.label.cex=.7,
     vertex.frame.color = 'white')

Figure 6. Network of latitude-zoned spider assemblages linked by shared barcodes shows that similarity increases with latitude. Vertices represent latitude zone and BIN richness; edges are wieghted by the number of shared BINs between zones.


Discussion

In this work I examined the latitudinal diversity gradient in DNA-barcoded spider specimens recorded in BOLD; as well as to evaluate geographical sampling bias in this collection. To this end, a number of ecological analysis were performed including rarefaction, species accumulation, and ordination. The Barcode of Life database (BOLD) contains a huge number of spider specimen records (124k) and associated DNA-barcode sequences (106k; table 1) (Ratnasingham and Hebert 2007, 2013). There is a surprisingly large number of unique DNA barcode indentifiers (BINs) compared to species names (9,845 vs 3,822). Additionally large number of specimens are missing taxonomic labels at the family, genus, and species levels (17k, 21k, and 23k records, respectively), indicating that barcode-based analysis is especially useful for spiders. Most barcodes have only a few specimens, and the number of specimens per barcode sequence has a negative binomial distribution (fig. 2 right)

To evaluate the global distribution of the sampling effort represented in the BOLD spider collection, all records having barcodes and geodata (96k) were binned into a 1 deg grid and mapped (fig. 1). Strong North American and European sampling bias is evident; vast swaths of Africa and Central Asia have no representatives. The sampling of spider specimens is heavily skewed to northern latitudes (fig. 2 left) though this is roughly proportional to overall landmass. While there are a large number of spider families represented in the dataset, a few families (Linyphiidae, Lycosidae and Araneidae) tend to dominate communities across latitudes.

Spiders biodiversity is generally known to decrease with distance from the equator (Platnick 1991; Piel 2018). To evaluate the latitudinal diversity gradient of the BOLD spiders data, I first grouped records into four ‘latitudinal communities’ based on absolute latitude: tropical (+/-0-20 deg), sub-tropical (20-40), temperate (40-60) and extreme (60+). Similarly, specimen-source countries were categorized into these zones based on the mean latitude of specimens collected in each country.

Diversity analyses of these national and latitudinal communities showed that diversity generally decreases with distance from the equator, as was expected from previous research (Platnick 1991; Piel 2018). Overall, the sub-tropical zone contained the greatest barcode (BIN) richness followed by the temperate and tropical zones (table 2, fig 2b.). Rarefaction analysis showed that the sub-tropical and tropical communities are fairly similar in terms of diversity and are more diverse than the temperate and extreme latitude zones (fig. 3b). When national communities are considered, we can see that there is a large degree of variance in diversity between countries at similar distances from the equator, and this is especially true for the communities of the few tropical nations examined (only fig. 3c,d).

When considering equal sample sizes, the sub-tropical zone had the greatest rarefied BIN richness but this was only slightly larger than the tropical zone (table 2, fig. 4). Temperate and extreme latitudes had relatively low Shannon diversity, while the subtropical-zone had a slightly greater Shannon diversity than the tropical zone. Simpson diversity was not very informative for differentiating communities at the zone or country level, with most values approaching 1. Anova tests of countries’ richness and Shannon index data showed that the differences in means between latitude zones were not statistically significant. This analysis was hindered by the low number of site countries having enough specimens (n>499, countries=21) and these were concentrated in the temperate and subtropical zones, leading to large error values in estimating the diversity of tropical and extreme zones. Overall, the BOLD spiders data follow the expected negative latitude-diversity trend; however, peak richness and diversity was observed in the sub-tropical zones (+/- 20-40 deg latitude).

Ordination and network analysis of latitude zone communities showed that the temperate and extreme zones were the most similar in composition and had the greatest number of shared BINs at 654 (figs. 5,6), representing 78% of the BINs from the extreme latitude community and 22% of the temperate community. This was contrasted by the relatively few bins shared between the tropical, sub-tropical, and temperate zones. From ordination, we see that the extreme and temperature communities are most similar in terms of composition while the sub-tropical and tropical zones are as dissimilar to the temperate and extreme zones as they are to each other.

The mapping of specimens and rarefaction curves produced from BIN abundances by country and latitude zone (fig. 2) both show a strong geographic bias in the database and an under-powered sampling of many regions, particularly at tropical latitudes. Despite the wide range of source countries, Canadian specimens account for nearly half the collection with the remaining records being predominantly from the US and handful of other countries. This ‘Boreal bias’ is a prevalent theme in ecology (Platnick 1991) and the BOLD data reflects this. As such, some results of this diversity analysis are particularly suspect. Brazil, for example, appears to have extremely low spider diversity but this is contrary to what is expected from the latitude-diversity trend and the highly-productive landscape.

In summary, BOLD data show decreasing trend in spider biodiversity with distance from the equator as has been previously described (Piel 2018, @Platnick1991). There is great variation in diversity between countries in the BOLD data and a limited number of tropical countries with adequate sampling. This made it difficult find significant changes in richness or diversity across latitudes. Sampling bias has affected the analysis to an extent but this is somewhat compensated for by the large volume of specimens collected and the use of broad latitude zones. The BOLD database is indeed a valuable resource for evaluating global ecological trends. BOLD’s value will continue to increase with the addition of collections from under-represented areas.

Code and supplemental

Please find the code used to create this work in the file JMogg_spider_diversity_notebook.nb.html where it is presented in the ‘literate programming’ style. This pdf document and the notebook were rendered from Rmarkdown files JMogg_spider_diversity_pdf.Rmd and JMogg_spider_diversity_notebook.Rmd, respectively. Figures have been labelled in the order that they appear in the pdf format.


Acknowledgements

We truly stand on the shoulders of giants and I found the following tutorials very helpful while creating this work:


References

Nyffeler, Martin, and Klaus Birkhofer. 2017. “An estimated 400-800 million tons of prey are annually killed by the global spider community.” Science of Nature 104 (3-4). https://doi.org/10.1007/s00114-017-1440-1.

Piel, William H. 2018. “The global latitudinal diversity gradient pattern in spiders.” Journal of Biogeography 45 (8): 1896–1904. https://doi.org/10.1111/jbi.13387.

Platnick, Norman I. 1991. “Patterns of biodiversity: Tropical vs temperate.” Journal of Natural History 25 (5): 1083–8. https://doi.org/10.1080/00222939100770701.

Ratnasingham, Sujeevan, and Paul D N Hebert. 2007. “The Barcode of Life Data System.” Molecular Ecology Notes 7 (April 2016): 355–64. https://doi.org/10.1111/j.1471-8286.2006.01678.x.

Ratnasingham, Sujeevan, and Paul D. N. Hebert. 2013. “A DNA-Based Registry for All Animal Species: The Barcode Index Number (BIN) System.” PLoS ONE 8 (7). https://doi.org/10.1371/journal.pone.0066213.

Tahir, Hafiz Muhammad, Muhammad Summer, Sana Mehmood, Sehrish Ashraf, and Sajida Naseem. 2019. “DNA barcoding of spiders from agricultural fields.” Mitochondrial DNA Part B: Resources 4 (2): 4144–51. https://doi.org/10.1080/23802359.2019.1693283.

Tyagi, Kaomud, Vikas Kumar, Shantanu Kundu, Avas Pakrashi, Priya Prasad, John T. D. Caleb, and Kailash Chandra. 2019. “Identification of Indian Spiders through DNA barcoding: Cryptic species and species complex.” Scientific Reports 9 (1): 1–13. https://doi.org/10.1038/s41598-019-50510-8.

LS0tCnRpdGxlOiBEaXZlcnNpdHkgYW5hbHlzaXMgb2YgKkFyYW5lYWUqIChzcGlkZXJzKSBzcGVjaW1lbnMgaW4gdGhlIEJhcmNvZGUgb2YgTGlmZQogIERhdGFiYXNlCmF1dGhvcjogIkphc29uIEEuIE1vZ2dyaWRnZSIKZGF0ZTogIjIwMjAvMTAvMDciCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogeWVzCiAgICBkZl9wcmludDogcGFnZWQKICAgIHRoZW1lOiBmbGF0bHkKICAgIGhpZ2hsaWdodDogdGV4dG1hdGUKYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYgotLS0KCipTdWdnZXN0aW9uOiB1c2Ugb3B0aW9uICdoaWRlIGFsbCBjb2RlJyBpbiB0aGUgbWVudSBhdCB0b3AtcmlnaHQsIHRoZW4gZXhwYW5kIGNvZGUgY2h1bmtzIHdoZW4gaW50ZXJlc3RlZC4qPGJyPgoqTm90ZTogVGltZSBjb25zdW1pbmcgY29tcHV0YXRpb25zIGhhdmUgYmVlbiAjLWNvbW1lbnRlZCBvdXQgZm9yIGNvbnZlbmllbmNlLCBhZnRlciBkYXRhIHdlcmUgc2F2ZWQqCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKCWVjaG8gPSBUUlVFLAoJbWVzc2FnZSA9IEZBTFNFLAoJd2FybmluZyA9IEZBTFNFCikKYGBgCgotLS0tLQoKIyBJbnRyb2R1Y3Rpb24KClNwaWRlcnMgYXJlIGFuIGluY3JlZGlibHkgZGl2ZXJzZSBvcmRlciBvZiBhcnRocm9wb2RzIHRoYXQgcGxheSB2aXRhbCByb2xlcyBpbiBkaXZlcnNlIGVjb3N5c3RlbXMsIHBhcnRpY3VsYXJseSBhcyBrZXkgcHJlZGF0b3JzIHRoYXQgbW9kdWxhdGUgYmlvbWFzcyBvbiBhIGdsb2JhbCBzY2FsZSBbQE55ZmZlbGVyMjAxN10uIFRoZXJlIGFyZSBjdXJyZW50bHkgNDgsNzg5IHNwZWNpZXMgZGVzY3JpYmVkIGluIHRoZSBXb3JsZCBzcGlkZXIgY2F0YWxvZyAoaHR0cHM6Ly93c2Mubm1iZS5jaC8pIGFuZCBub3ZlbCBzcGVjaWVzIGFyZSBiZWluZyBhZGRlZCBvbiBhIHJlZ3VsYXIgYmFzaXMuIERpZmZlcmVudGlhdGlvbiBvZiBzdWNoIGEgbGFyZ2UgbnVtYmVyIG9mIHNwZWNpZXMgYmFzZWQgb24gbW9ycGhvbG9neSBhbG9uZSBpcyB0cmVtZW5kb3VzbHkgY2hhbGxlbmdpbmcuIFRoaXMgZGlmZmljdWx0eSBpcyBjb21wb3VuZGVkIGJ5IG90aGVyIGluY29udmVuaWVudCBjaGFyYWN0ZXJpc3RpY3Mgb2Ygc3BpZGVycyBpbmNsdWRpbmcgc2V4dWFsIGRpbW9ycGhpc20sIGRldmVsb3BtZW50YWwgY2hhbmdlcyBpbiBtb3JwaG9sb2d5LCBhbmQgdGhlaXIgY3J5cHRpYyBsaWZlc3R5bGVzIFtAVHlhZ2kyMDE5XS4KCkFzIG1vcnBob2xvZ2ljYWwgY2xhc3NpZmljYXRpb24gb2YgbGFyZ2UgbnVtYmVycyBvZiBzcGlkZXJzIGlzIGdlbmVyYWxseSB0ZWRpb3VzIGFuZCBpbXByYWN0aWNhbCwgRE5BIGJhcmNvZGluZyBoYXMgYmVjb21lIHJvdXRpbmUgbWV0aG9kIGZvciBzcGVjaWVzIGlkZW50aWZpY2F0aW9uIGluIGVjb2xvZ2ljYWwgc3R1ZGllcyBbQFRhaGlyMjAxOV0uIFRoZSBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIG1pdG9jaG9uZHJpYWwgKmN5dG9jaHJvbWUgYyBveGlkYXNlKiBzdWJ1bml0IDEgKENPMSkgZ2VuZSBtYWtlIGl0IGFuIGlkZWFsIG1hcmtlciBmb3IgZGlmZmVyZW50aWF0aW5nIHNwZWNpZXMgW0BSYXRuYXNpbmdoYW0yMDA3OyBAUmF0bmFzaW5naGFtMjAxM10uIEluIGEgcmVsYXRpdmVseSBsaW1pdGVkIHRpbWUsIGEgbGFyZ2UgYW1vdW50IG9mIGJhcmNvZGUgc2VxdWVuY2VzIGhhdmUgYmVlbiBhY2N1bXVsYXRlZCBpbiB0aGUgQmFyY29kZSBvZiBMaWZlIERhdGFiYXNlLCBtYWtpbmcgaXQgYSB1c2VmdWwgcmVzb3VyY2UgZm9yIGVjb2xvZ3kgcmVzZWFyY2guCgpTcGlkZXIgZGl2ZXJzaXR5IGdlbmVyYWxseSBkZWNyZWFzZXMgd2l0aCBkaXN0YW5jZSBmcm9tIHRoZSBlcXVhdG9yIFtAUGllbDIwMThdLiBUaGVyZSBpcyBzb21lIGRlYmF0ZSBhcyB0byB3aGV0aGVyIHRoZSBkaXN0cmlidXRpb24gaXMgZXZlbiBiZXR3ZWVuIGhlbWlzcGhlcmVzIG9yIHBlYXItc2hhcGVkIHdpdGggdGhlIHNvdXRoZXJuIGhlbWlzcGhlcmUgYmVpbmcgbW9yZSBkaXZlcnNlLiBJbiB0aGlzIHdvcmssIEkgZXhhbWluZWQgd2hldGhlciB0aGUgY29sbGVjdGlvbiBvZiBETkEtYmFyY29kZWQgc3BpZGVyIHNwZWNpbWVucyBpbiB0aGUgQk9MRCBkYXRhYmFzZSBzaG93cyB0aGUgZGl2ZXJzaXR5IHRyZW5kIGFjcm9zcyBsYXRpdHVkZXMgYXMgaXMgcmVwb3J0ZWQgaW4gdGhlIGxpdGVyYXR1cmUuIEFkZGl0aW9uYWxseSwgc2FtcGxpbmcgZGVwdGggYW5kIGdlb2dyYXBoaWMgYmlhcyBvZiB0aGUgQk9MRCBkYXRhIHdlcmUgZXZhbHVhdGVkLgoKLS0tLS0KICAKIyBBbmFseXNpcyBhbmQgUmVzdWx0cwoKCiMjIyBTb2Z0d2FyZS9MaWJyYXJpZXMKClRoaXMgd29yayB3YXMgcHJvZHVjZWQgd2l0aCB0aGUgUiBsYW5ndWFnZSBhbmQgdGhlIGZvbGxvd2luZyBwYWNrYWdlczoKCmBgYHtyIHBja2dzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIHBhY2thZ2VzIHVzZWQKbGlicmFyeShib2xkKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeSh2ZWdhbikKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShndCkKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KHJjYXJ0b2NvbG9yKQpsaWJyYXJ5KGlncmFwaCkKbGlicmFyeShwbG90bHkpCmBgYAo8YnI+CgotLS0tCgojIyMgRG93bmxvYWRpbmcgQk9MRCBzcGVjaW1lbiByZWNvcmRzCgpBbGwgc3BlY2ltZW4gcmVjb3JkcyBmb3IgKkFyYW5lYWUqIHdlcmUgZG93bmxvYWRlZCBmcm9tIHRoZSBCT0xEIGFwaSBvbiAyMDIwLTA5LTI5LiAKSSBhbHNvIG9idGFpbmVkIHRoZSBXb3JsZCBzcGlkZXIgY2F0YWxvZyBkYXRhc2V0IChvbiB0aGUgc2FtZSBkYXRlKSBhcyBhIHJlZmVyZW5jZSBmb3IgY29tcGFyaXNvbiBvZiB0YXhvbm9taWMgaWRlbnRpZmllcnMuCgoKYGBge3IgZG93bmxvYWQsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUV9CiMjIGJ1aWxkIHRoZSB1cmwgZm9yIGRvd25sb2FkaW5nCiMgdGF4b24gPC0gIkFyYW5lYWUiCiMgdGF4b24gPC0gcGFzdGUwKCJ0YXhvbj0iLCB0YXhvbikKIyBwcmVmaXggPC0gImh0dHA6Ly93d3cuYm9sZHN5c3RlbXMub3JnL2luZGV4LnBocC9BUElfUHVibGljL3NwZWNpbWVuPyIKIyBmbXQgPC0gIiZmb3JtYXQ9dHN2IgojIHVybCA8LSBwYXN0ZTAocHJlZml4LCB0YXhvbiwgZm10KQojIAojICMgZG93bmxvYWQsIHBhcnNlIGRhdGEKIyBBcmFuZWFlLmRmIDwtIHJlYWRfZGVsaW0odXJsLCBkZWxpbSA9ICdcdCcsZ3Vlc3NfbWF4ID0gMTAwMDApCiMgd3JpdGVfcmRzKEFyYW5lYWUuZGYsICIuL2RhdGEvQk9MRC5hcmFuZWFlLnJkcyIpCiMgCmBgYAoKCi0tLS0tCgojIyMgQk9MRCAnQXJhbmFlYScgZGF0YXNldAoKVGhlIGRhdGFzZXQgdXNlZCBpbiB0aGlzIGFuYWx5c2lzIGNvbnRhaW5lZCBhbGwgdGhlIGF2YWlsYWJsZSBzcGVjaW1lbiByZWNvcmRzIG9mIHRoZSBvcmRlciAqQXJhY2VhZSouIApBbnkgcmVjb3JkcyBsYWNraW5nIEJJTiBpZGVudGlmaWVycyBvciBnZW9ncmFwaGljIG1ldGFkYXRhIHdlcmUgcmVtb3ZlZC4gClRoZXJlIGFyZSA5NSw0Nzkgc3BlY2ltZW4gcmVjb3JkcyBpbiB0aGlzIHNlbGVjdGlvbiwgcmVwcmVzZW50aW5nIDksNzU3IEJJTiBjbHVzdGVycyBhbmQgdGhlc2Ugd2VyZSBjb2xsZWN0ZWQgaW4gMTM2IGNvdW50cmllcy4KU3BlY2ltZW4gcmVjb3JkcyB3ZXJlIGdyb3VwZWQgYnkgYWJzb2x1dGUgbGF0aXR1ZGUgYW5kIGNsYXNzaWZpZWQgYXMgdHJvcGljYWwgKDAtMjDLmiksIHN1Yi10cm9waWNhbCAoMjAtNDDLmiksIHRlbXBlcmF0ZSAoNDAtNjDLmiksIG9yIGV4dHJlbWUgKDYwLTkwy5opLiAKU2ltaWxhcmx5LCBjb3VudHJpZXMgd2VyZSBncm91cGVkIGJ5IHRoZWlyIG1lYW4gbGF0aXR1ZGUgb2YgYWxsIHNwZWNpbWVucyBmb3IgZGl2ZXJzaXR5IGFuYWx5c2VzLgoKCmBgYHtyIHByb2Nlc3NpbmcsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUV9CiMgcmVhZCBpbiBwcmV2aW91c2x5IGRvd25sb2FkZWQgZGF0YSBzZXRzCiMgU3BpZGVyX2NhdGFsb2cuZGYgPC0gcmVhZF9yZHMoIi4vZGF0YS9zcGlkZXJfY2F0YWxvZy5yZHMiKQpBcmFuZWFlLnJhdyA8LSByZWFkX3JkcygiLi9kYXRhL0JPTEQuYXJhbmVhZS5yZHMiKQoKIyB0aWR5IHVwIGRhdGEgYW5kIHJlbW92ZSB0aG9zZSBtaXNzaW5nIGNvdW50cnkgb3IgYmluIGRhdGEKQXJhbmVhZS5kZiA8LSBBcmFuZWFlLnJhdyAlPiUKICAjIEtlZXAgb25seSB1c2VmdWwgZGF0YSBjb2x1bW5zCiAgc2VsZWN0KHJlY29yZElELCBiaW5fdXJpLCBmYW1pbHlfbmFtZSwgZ2VudXNfbmFtZSwgc3BlY2llc19uYW1lLAogICAgICAgICBjb3VudHJ5LCBwcm92aW5jZV9zdGF0ZSwgbGF0LCBsb24sIGVsZXYpICAlPiUKICAjIEV4Y2x1ZGUgYW55IHJlY29yZCB0aGF0IGlzIG1pc3NpbmcgQklOIG9yIENvdW50cnkgbGFiZWxzCiAgZmlsdGVyKCFpcy5uYShiaW5fdXJpKSAmICFpcy5uYShjb3VudHJ5KSkgICU+JQogICMgQW55IG1pc3NpbmcgdGF4b25vbWljIGxhYmVscyBhcmUgcmVwbGFjZWQgd2l0aCAnVW5rbm93bicKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmNoYXJhY3RlciksIH5hcy5mYWN0b3IocmVwbGFjZV9uYSgueCwgJ1Vua25vd24nKSkpKSAlPiUKICAjIENyZWF0ZSBuZXcgdmFyaWFibGUgdG8gZ3JvdXAgcmVjb3JkcyBieSBjbGltYXRlIHpvbmUKICBtdXRhdGUoem9uZSA9IGFzLmZhY3RvcihjYXNlX3doZW4oCiAgICBhYnMobGF0KSA8PSAyMCB+ICdUcm9waWNhbCcsCiAgICBhYnMobGF0KSA+IDIxICYgYWJzKGxhdCkgPD0gNDAgIH4gJ1N1Yi10cm9waWNhbCcsCiAgICBhYnMobGF0KSA+IDQwICYgYWJzKGxhdCkgPD0gNjAgIH4gJ1RlbXBlcmF0ZScsCiAgICBhYnMobGF0KSA+IDYwIH4gJ0V4dHJlbWUnLAogICkpCiAgKQoKIyBBc3NpZ25pbmcgY291bnRyaWVzIHRvIGxhdGl0dWRlIHpvbmVzIGJhc2VkIG9uIG1lYW4gbGF0aXR1ZGUKY291bnRyeV96b25lcyA8LSBBcmFuZWFlLmRmICU+JQogIGdyb3VwX2J5KGNvdW50cnkpICU+JQogIHN1bW1hcmlzZShsYXQubWVhbiA9IG1lYW4obGF0LCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHpvbmUgPSBhcy5mYWN0b3IoY2FzZV93aGVuKAogICAgYWJzKGxhdC5tZWFuKSA8PSAyMCB+ICdUcm9waWNhbCcsCiAgICBhYnMobGF0Lm1lYW4pID4gMjAgJiBhYnMobGF0Lm1lYW4pIDw9IDQwICB+ICdTdWItdHJvcGljYWwnLAogICAgYWJzKGxhdC5tZWFuKSA+IDQwICYgYWJzKGxhdC5tZWFuKSA8PSA2MCAgfiAnVGVtcGVyYXRlJywKICAgIGFicyhsYXQubWVhbikgPiA2MCB+ICdFeHRyZW1lJywKICApKSkgJT4lCiAgIyBpZ25vcmUgYW55IGNvdW50cmllcyB0aGF0IHdlcmVuJ3QgbGFiZWxsZWQKICBmaWx0ZXIoIWlzLm5hKHpvbmUpKSAlPiUKICBtdXRhdGUoQ291bnRyeSA9IGNvdW50cnkpICU+JQogIHNlbGVjdChDb3VudHJ5LCBjb3VudHJ5LCB6b25lKQogIAojIGNvdW50cnlfem9uZXMKCiMgdGFibGUgb2YgYmFzaWMgc3RhdGlzdGljcyBhYm91dCBzcGVjaW1lbiByZWNvcmRzIGZyb20gQk9MRApkYXRhX3N1bW1hcnkgPC0gdGliYmxlKAogIENoYXJhY3RlcmlzdGljID0gYygKICAgICdTcGVjaW1lbiByZWNvcmRzIGluIEJPTEQnLAogICAgJ1JlY29yZHMgc2VsZWN0aW9uIChub3QgbWlzc2luZyBCSU4gYW5kIGNvdW50cnkgZGF0YSknLAogICAgJ051bWJlciBvZiB1bmlxdWUgQklOcyBpbiBzZWxlY3RlZCByZWNvcmRzJywKICAgICdVbmlxdWUgZmFtaWx5IHRheGEnLCAnVW5pcXVlIGdlbnVzIHRheGEnLCAnVW5pcXVlIHNwZWNpZXMgdGF4YScsCiAgICAnU291cmNlIGNvdW50cmllcyBpbiBzZWxlY3RlZCByZWNvcmRzJywKICAgICdMYXRpdHVkZSByYW5nZScpLAogIFZhbHVlID0gYygKICAgIGNvbW1hKG5yb3coQXJhbmVhZS5yYXcpKSwKICAgIGNvbW1hKG5yb3coQXJhbmVhZS5kZikpLAogICAgY29tbWEobGVuZ3RoKHVuaXF1ZShBcmFuZWFlLmRmJGJpbl91cmkpKSksCiAgICBsZW5ndGgodW5pcXVlKEFyYW5lYWUuZGYkZmFtaWx5X25hbWUpKSwKICAgIGNvbW1hKGxlbmd0aCh1bmlxdWUoQXJhbmVhZS5kZiRnZW51c19uYW1lKSkpLAogICAgY29tbWEobGVuZ3RoKHVuaXF1ZShBcmFuZWFlLmRmJHNwZWNpZXNfbmFtZSkpKSwKICAgIGxlbmd0aCh1bmlxdWUoQXJhbmVhZS5kZiRjb3VudHJ5KSksCiAgICBwYXN0ZTAocm91bmQobWluKEFyYW5lYWUuZGYkbGF0LCBuYS5ybSA9IFRSVUUpLCAxKSwKICAgICAgICAgICAnIDogJywgcm91bmQobWF4KEFyYW5lYWUuZGYkbGF0LCBuYS5ybSA9IFRSVUUpLCAxKSkKICApKQoKIyB0YWJ1bGF0ZSBuIHNwZWNpbWVucyBhbmQgc3BlY2llcyBieSBjb3VudHJ5IGZvciBhcnJhbmdpbmcgY291bnRyaWVzIGJ5IG4gc3BlY2ltZW5zIGFuZCBiaW5zCmNvdW50cnkuc3BlY2ltZW5zLnRhYmxlIDwtIEFyYW5lYWUuZGYgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lCiAgc3VtbWFyaXplKHNwZWNpbWVucyA9IG4oKSwKICAgICAgICAgICAgc3BlY2llcyA9IGxlbmd0aCh1bmlxdWUoYmluX3VyaSkpKSAlPiUKICBhcnJhbmdlKGRlc2Moc3BlY2llcykpICU+JQogIGxlZnRfam9pbihjb3VudHJ5X3pvbmVzICU+JSBzZWxlY3QoY291bnRyeSwgem9uZSkpCgpgYGAKIApcaGZpbGxcYnJlYWsgIAoKKipUYWJsZSAxKiouIFN1bW1hcnkgb2YgKkFyYW5lYWUqIHNwZWNpbWVuIHJlY29yZHMgZnJvbSB0aGUgQk9MRCBkYXRhYmFzZSB0aGF0IHdlcmUgdXNlZCBpbiB0aGlzIGFuYWx5c2lzLiAKICAgICAKYGBge3Igc3VtbWFyeS50YWJsZSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0Ka2FibGUoZGF0YV9zdW1tYXJ5LCBmb3JtYXQgPSAncGlwZScsZXNjYXBlID0gVFJVRSkKYGBgCiAKLS0tLS0KCiMjIyBTcGVjaW1lbiBNYXAKCkEgbWFwIHNob3dpbmcgdGhlIGdlb2dyYXBoaWMgZGlzdHJpYnV0aW9uIG9mIHNwaWRlciBzcGVjaW1lbnMgaW4gdGhlIEJPTEQgZGF0YWJhc2UuIFN0cm9uZyBOb3J0aCBBbWVyaWNhbiBhbmQgRXVyb3BlYW4gc2FtcGxpbmcgYmlhcyBpcyBldmlkZW50OyB0aGUgU291dGhlcm4gaGVtaXNwaGVyZSBpcyBub3Qgd2VsbCByZXByZXNlbnRlZCwgZXNwZWNpYWxseSBBZnJpY2EgYW5kIENlbnRyYWwgQXNpYS4KICAgCmBgYHtyIHNwaWRlci5tYXAsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUV9CiMjIGdyb3VwIHNwZWNpbWVucyBvbiBhIDFkZWcgZ3JpZApzcGlkZXIubWFwLmRmIDwtIEFyYW5lYWUuZGYgJT4lCiAgIyByb3VuZCBjb29yZHMgdG8gbmVhcmVzdCBkZWcuCiAgbXV0YXRlKGxhdCA9IHJvdW5kKGxhdCksCiAgICAgICAgIGxvbiA9IHJvdW5kKGxvbikpICU+JQogICMgZ3JvdXAvY291bnQgYWxsIHNwZWNpbWVucyB3aXRoIHNhbWUgY29vcmRzCiAgZ3JvdXBfYnkobGF0LCBsb24pICU+JQogIG11dGF0ZShuPW4oKSwKICAgICAgICAgQklOcyA9IGxlbmd0aCh1bmlxdWUoYmluX3VyaSkpKSAlPiUKICBzZWxlY3QobGF0LCBsb24sIG4sIEJJTnMpICU+JQogIGRpc3RpbmN0KCkgJT4lCiAgIyBjcmVhdGUgcG9wdXAgbGFiZWxzIHdpdGggaW5mbwogIG11dGF0ZShwb3B1cHMgPSBwYXN0ZTAoCiAgICAiPGI+TGF0OiA8L2I+IiwgbGF0LAogICAgJzxicj48Yj5Mb25nOiA8L2I+JywgbG9uLAogICAgIjxicj48Yj5TcGVjaW1lbnM6IDwvYj4iLCBuLAogICAgIjxicj48Yj5CSU5zOiA8L2I+IiwgQklOcyksCiAgICBsYWJzID0gcGFzdGUobiwgJ3NwZWNpbWVucycpCiAgICApICU+JQogIGZpbHRlcighKGlzLm5hKGxhdCl8aXMubmEobG9uKSkpCgoKIyBjcmVhdGUgbWFwCgptYWtlLnNwaWRlci5tYXAgPC0gZnVuY3Rpb24oc3BpZGVyLm1hcC5kZil7CiAgCiAgc3BpZGVyLm1hcCA8LSBsZWFmbGV0KHNwaWRlci5tYXAuZGYpICU+JQogICAgc2V0Vmlldyh6b29tPTEsIGxhdD0zMCwgbG5nPTUpICU+JQogICAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgCiAgCiAgIyBhZGQgbGF0aXR1ZGUgbGluZXMgdGhhdCBzYW1wbGVzIHdlcmUgZ3JvdXBlZCBieQogIGZvciAoaSBpbiBjKC02MCwgLTQwLCAtMjAsIDAsIDIwLCA0MCwgNjApKSB7CiAgICBzcGlkZXIubWFwIDwtIHNwaWRlci5tYXAgJT4lCiAgICAgIGFkZFBvbHlsaW5lcyhsbmcgPSBjKC0zNjA6MzYwLCAzNjA6LTM2MCksIAogICAgICAgICAgICAgICAgICAgbGF0ID0gcmVwKGksIHRpbWVzPTcyMCksIHdlaWdodCA9IDAuNCkKICB9CiAgCiAgc3BpZGVyLm1hcCA8LSBzcGlkZXIubWFwICU+JQogICAgYWRkQ2lyY2xlTWFya2VycygKICAgICAgY29sb3IgPSAnI2YyMDAwMCcsCiAgICAgIGxuZyA9IH5sb24sCiAgICAgIGxhdCA9IH5sYXQsCiAgICAgIHJhZGl1cyA9IH4obG9nKG4pKzEpKjAuNCwKICAgICAgZmlsbE9wYWNpdHkgPSAwLjMsCiAgICAgIHN0cm9rZSA9IEZBTFNFLAogICAgICBwb3B1cCA9IH5wb3B1cHMsCiAgICAgIGxhYmVsID0gfmxhYnMKICAgICkgIAogIHJldHVybihzcGlkZXIubWFwKQp9CgptYWtlLnNwaWRlci5tYXAoc3BpZGVyLm1hcC5kZikKYGBgCgoqKkZpZ3VyZSAxLiBHZW9ncmFwaHkgb2YgQk9MRCBzcGlkZXIgc3BlY2ltZW5zKiouIE1hcmtlcnMgc2hvdyB0aGUgbG9jYXRpb24gYW5kIGFtb3VudCBvZiBzcGVjaW1lbnMgY29sbGVjdGVkIGF0IGVhY2ggbG9jYXRpb247IHNwZWNpbWVucyB3ZXJlIGJpbm5lZCBpbnRvIGEgMWRlZyB4IDFkZWcgZ3JpZCBmb3IgY291bnRpbmcuIExhdGl0dWRlIGxpbmVzIGNvcnJlc3BvbmQgdG8gdGhlIHpvbmVzIHRoYXQgd2VyZSBjb25zaWRlcmVkIGluIHRoZSBnZW9ncmFwaGljIGFuYWx5c2lzIG9mIHNwaWRlciBkaXZlcnNpdHkuICooQW4gaW50ZXJhY3RpdmUgdmVyc2lvbiB3aXRoIHpvb20gJiBsYWJlbHMgaXMgcHJlc2VudGVkIGluIHRoZSBhY2NvbXBhbnlpbmcgaHRtbC1ub3RlYm9vayAnSk1vZ2dfc3BpZGVyX2RpdmVyc2l0eV9ub3RlYm9vay5odG1sJykqCgogICAgCiMjIyBDb21wb3NpdGlvbiBhbmQgc2FtcGxpbmcgZGVwdGggYnkgbGF0aXR1ZGUKCmBgYHtyIGJhcl9mYW1pbGllcywgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9NywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0KIyB0YWJsdWxhdGUgc3BlY2ltZW4gcmVjb3JkcyBjb3VudCBieSBCSU4KYmluLnRhYmxlIDwtIEFyYW5lYWUuZGYgJT4lCiAgY291bnQoYmluX3VyaSkKCiMgcGxvdCBoaXN0b2dyYW0gb2Ygc3BlY2ltZW4gY291bnRzIGZvciBCSU5zIChiaW4gc2l6ZSBkaXN0cmlidXRpb24pCgpiaW4uaGlzdCA8LSBiaW4udGFibGUgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbikpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAwKSArCiAgc2NhbGVfeF9sb2cxMCgpICsgc2NhbGVfeV9sb2cxMCgpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpICsKICBsYWJzKHggPSAnU3BlY2ltZW5zIGFzc2lnbmVkIHRvIEJJTicsCiAgICAgICB5ID0gJ0ZyZXF1ZW5jeScpICsKICB0aGVtZV9jbGFzc2ljKCkKICAKIyBBcmFuZWFlLmRmMiA8LSBBcmFuZWFlLmRmICU+JQojICAgbXV0YXRlKHBsb3RseS5sYWJzID0gcGFzdGUoIjxiPkxhdDo8L2I+IiwgbGF0LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxicj48Yj5GYW1pbHk8L2I+OiwgZmFtaWx5X25hbWUpKQojIFNwZWNpbWVuIGRpc3RyaWJ1dGlvbiBieSBsYXRpdHVkZQpzcGVjLmxhdHMuYmFyIDwtIGdncGxvdChBcmFuZWFlLmRmLCBhZXMoeT1sYXQsIGZpbGwgPSBmYW1pbHlfbmFtZSkpICsKICBnZW9tX2hpc3RvZ3JhbShhbHBoYSA9IDAuOCwgY29sb3VyID0gJ2xpZ2h0Z3JleScsIG9yaWVudGF0aW9uID0gJ3knLAogICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb24gPSAnQycpICsKICBsYWJzKHkgPSAnTGF0aXR1ZGUnLCB4ID0gJ1NwZWNpbWVuIGNvdW50JykgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ251bGwnKQoKIyBzaG93IGJvdGggcGxvdHMKCmdncGxvdGx5KHNwZWMubGF0cy5iYXIpCmBgYAoKKipGaWd1cmUgMmEuKiogQSBwbG90IHNob3dpbmcgdGhlIG51bWJlciBvZiBzYW1wbGVzIGNvbGxlY3RlZCBieSBsYXRpdHVkZTsgY29sb3JzIGNvcnJlc3BvbmQgdG8gZGlmZmVyZW50IHNwaWRlciBmYW1pbGllczsgcG9wdXAgbGFiZWxzIHNob3cgZmFtaWx5IG5hbWUgYW5kIHNwZWNpbWVuIGNvdW50IC0gcGxlYXNlIGlnbm9yZSBsYXRpdHVkZSBpbiBwb3B1cCBsYWJlbHMgYW5kIHJlYWQgZnJvbSB5LWF4aXMuIEZhbWlsaWVzIGNhbiBiZSBoaWRkZW4vcmV2ZWFsZWQgYnkgY2xpY2tpbmcgaWNvbnMgb24gdGhlIGxlZ2VuZCAoc2Nyb2xsIHRvIGJyb3dzZSkuCgpgYGB7ciBiaW4uIGhpc3QsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0KYmluLmhpc3QKYGBgCiAgICAKICAgIAoKCioqRmlndXJlIDJiLioqICBBIGhpc3RvZ3JhbSBzaG93aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIG51bWJlciBvZiBzcGVjaW1lbnMgdGhhdCBoYXZlIGJlZW4gYXNzaWduZWQgdG8gZWFjaCBCSU4uCiAgIAotLS0tLQoKCiMjIyBDb21tdW5pdHkgYWJ1bmRhbmNlcyAmIGFscGhhLWRpdmVyc2l0eSBhbmFseXNpcwoKQ29tbXVuaXR5IGFidW5kYW5jZSB0YWJsZXMgd2VyZSBjcmVhdGVkIGZvciB0aGUgZW50aXJlIGRhdGFzZXQsIGJ5IGNvdW50cnkgYW5kIGJ5IGxhdGl0dWRlIHpvbmUgZm9yIGRpdmVyc2l0eSBhbmFseXNlcyB3aXRoIHRoZSBgdmVnYW5gIHBhY2thZ2UuCgoKYGBge3IgY29tbXVuLmFidW5kLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojICMgY3JlYXRpbmcgY29tbXVuaXR5IGFidW5kYW5jZSBtYXRyaWNlcyBmb3IgdmVnYW4gZnVuY3Rpb25zCiMgIyBNYWtlIHRhYmxlcyB3aXRoIGJpbnMgYXMgY29sdW1ucyArIHJlcGxhY2UgbWlzc2luZyB2YWx1ZXMgd2l0aCB6ZXJvZXMKIyAKIyAjIEJpbiBjb3VudHMgZnJvbSBmdWxsIGRhdGFzZXQKIyBBcmFuZWFlLmRmLmJpbnMgPC0gQXJhbmVhZS5kZiAlPiUKIyAgICMgY291bnQgc3BlY2ltZW5zCiMgICBjb3VudChiaW5fdXJpKSAlPiUKIyAgICMgbWFrZSB3aWRlIHRhYmxlCiMgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYmluX3VyaSwgdmFsdWVzX2Zyb20gPSBuKQojIHdyaXRlX3JkcyhBcmFuZWFlLmRmLmJpbnMsICIuL2RhdGEvQXJhbmVhZS5iaW5zLnJkcyIpCiMgCiMgIyBjb21tdW5pdHkgbWF0cml4IHdpdGggY291bnRyaWVzIGFzIG9ic2VydmF0aW9ucyAKIyAjIG11c3QgbWFrZSBzaXRlIGludG8gcm93bmFtZXMKIyBBcmFuZWFlLmNvdW50cnkuYmlucyA8LSBBcmFuZWFlLmRmICU+JQojICAgY291bnQoYmluX3VyaSwgY291bnRyeSkgJT4lCiMgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYmluX3VyaSwgdmFsdWVzX2Zyb20gPSBuKSAlPiUKIyAgICMgcmVwbGFjZSBOQSB3aXRoIDAgdmFsdWVzCiMgICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+cmVwbGFjZV9uYSgueCwgMCkpKSAgJT4lCiMgICAjIG1ha2Ugc2l0ZSBsYWJlbHMgaW50byBkZiByb3duYW1lcwojICAgcmVtb3ZlX3Jvd25hbWVzICU+JQojICAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJjb3VudHJ5IikKIyB3cml0ZV9yZHMoQXJhbmVhZS5jb3VudHJ5LmJpbnMsICIuL2RhdGEvQXJhbmVhZS5jb3VudHJ5LmJpbnMucmRzIikKIyAKIyAjIGNvbW11bml0eSBtYXRyaXggd2l0aCBsYXRpdHVkZSB6b25lcyBhcyBvYnNlcnZhdGlvbnMKIyBBcmFuZWFlLnpvbmUuYmlucyA8LSBBcmFuZWFlLmRmICU+JQojICAgY291bnQoYmluX3VyaSwgem9uZSkgJT4lCiMgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYmluX3VyaSwgdmFsdWVzX2Zyb20gPSBuKSAlPiUKIyAgIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH5yZXBsYWNlX25hKC54LCAwKSkpICU+JQojICAgZmlsdGVyKCFpcy5uYSh6b25lKSkgJT4lCiMgICByZW1vdmVfcm93bmFtZXMgJT4lCiMgICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInpvbmUiKQojIHdyaXRlX3JkcyhBcmFuZWFlLnpvbmUuYmlucywgIi4vZGF0YS9BcmFuZWFlLnpvbmUuYmlucy5yZHMiKQpgYGAKCgoKClJpY2huZXNzIG9mIEJJTnMgYW5kIHJhcmVmaWVkIHJpY2huZXNzIChzYW1wbGU9NTAwKSwgU2hhbm5vbiBkaXZlcnNpdHksIGFuZCBTaW1wc29uIGRpdmVyc2l0eSB3ZXJlIGNhbGN1bGF0ZWQgZm9yIGVhY2ggY291bnRyeSBhbmQgZWFjaCBsYXRpdHVkZSB6b25lcy4KCgpgYGB7ciBhbHBoYSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0KIyBjb21tdW5pdHkgYWJ1bmRhbmNlIG1hdHJpY2VzIG1hZGUgaW4gcHJldmlvdXMgY29kZSBjaHVuawpBcmFuZWFlLmJpbnMgPC0gcmVhZF9yZHMoIi4vZGF0YS9BcmFuZWFlLmJpbnMucmRzIikKQXJhbmVhZS56b25lLmJpbnMgPC0gcmVhZF9yZHMoIi4vZGF0YS9BcmFuZWFlLnpvbmUuYmlucy5yZHMiKQpBcmFuZWFlLmNvdW50cnkuYmlucyA8LSByZWFkX3JkcygiLi9kYXRhL0FyYW5lYWUuY291bnRyeS5iaW5zLnJkcyIpCgpjb3VudHJ5LmJpbnMuNTAwIDwtIEFyYW5lYWUuY291bnRyeS5iaW5zICU+JQogIGJpbmRfY29scyhzdW0gPSByb3dTdW1zKEFyYW5lYWUuY291bnRyeS5iaW5zKSkgJT4lCiAgZmlsdGVyKHN1bSA+IDUwMCkgJT4lCiAgc2VsZWN0KC1zdW0pCgojIGNhbGN1bGF0ZSByaWNobmVzcyAmIGFscGhhIGRpdmVyc2l0eSBtZXRyaWNzIGZvciBlYWNoIGNvdW50cnkKYWxwaGEuZGl2ZXJzaXR5LmNvdW50cnkgPC0gZGF0YS5mcmFtZShDb3VudHJ5PXJvd25hbWVzKGNvdW50cnkuYmlucy41MDApKSAlPiUKICBiaW5kX2NvbHMoCiAgICBsaXN0KAogICAgICBTcGVjaW1lbnMgPSByb3dTdW1zKGNvdW50cnkuYmlucy41MDApLAogICAgICBSaWNobmVzcyA9IHJvd1N1bXMoY291bnRyeS5iaW5zLjUwMCA+IDApLAogICAgICBgUmFyZWZpZWRgID0gdmVnYW46OnJhcmVmeShjb3VudHJ5LmJpbnMuNTAwLCBzYW1wbGUgPSA1MDApLAogICAgICBTaGFubm9uID0gdmVnYW46OmRpdmVyc2l0eShjb3VudHJ5LmJpbnMuNTAwLCBpbmRleCA9ICdzaGFubm9uJyksCiAgICAgIFNpbXBzb24gPSB2ZWdhbjo6ZGl2ZXJzaXR5KGNvdW50cnkuYmlucy41MDAsIGluZGV4ID0gJ3NpbXBzb24nKQogICAgKQogICAgKSAlPiUKICAjIHJvdW5kIG51bWJlcnMgb2ZmIHRvIDIgZGVjaW1hbHMKICBtdXRhdGUoU2hhbm5vbiA9IHJvdW5kKFNoYW5ub24sIDIpLAogICAgICAgICBTaW1wc29uID0gcm91bmQoU2ltcHNvbiwgMikpICU+JQogIGFycmFuZ2UoZGVzYyhTcGVjaW1lbnMpKSAlPiUKICBsZWZ0X2pvaW4oY291bnRyeV96b25lcyAlPiUgc2VsZWN0KC1jb3VudHJ5KSwgYnkgPSAnQ291bnRyeScpCgojIGthYmxlKGFscGhhLmRpdmVyc2l0eS5jb3VudHJ5LCBmb3JtYXQgPSAnc2ltcGxlJykKCnJpY2hfc3BlY2llc19sbSA8LSBnZ3Bsb3QoYWxwaGEuZGl2ZXJzaXR5LmNvdW50cnksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PWxvZyhTcGVjaW1lbnMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZyhSaWNobmVzcykpKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0pICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHpvbmUpKSArCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IENvdW50cnksIGNvbG9yID0gem9uZSkpICsKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZSgiTGF0LiB6b25lIikgKwogIHRoZW1lX2NsYXNzaWMoKQojIHJpY2hfc3BlY2llc19sbQoKIyMjIyMjIyMjIwoKIyBhcnJhbmdpbmcgbGFiZWxzIGZvciBwbG90IGJlbG93IChsZXhpY28gc29ydCB5LWF4aXMgY291bnRyaWVzKSAgICAKYWxwaGEuZGl2ZXJzaXR5LmNvdW50cnkkQ291bnRyeSA8LSBmYWN0b3IoYWxwaGEuZGl2ZXJzaXR5LmNvdW50cnkkQ291bnRyeSwgbGV2ZWxzPXJldihzb3J0KGFscGhhLmRpdmVyc2l0eS5jb3VudHJ5JENvdW50cnkpKSkKCiMgYXJyYW5naW5nIGRhdGEgdG8gbG9uZyBmb3JtIHdpdGggZGl2ZXJzaXR5IGluZGljZSArIHZhbHVlIHJvd3MgZm9yIGVhIGNvdW50cnkKYWxwaGEuY291bnRyeS5sb25nIDwtIGFscGhhLmRpdmVyc2l0eS5jb3VudHJ5ICU+JQogIHBpdm90X2xvbmdlcihSYXJlZmllZDpTaW1wc29uKSAlPiUKICBhcnJhbmdlKGRlc2MoQ291bnRyeSkpIAoKIyByZWFycmFuZ2UgZ3JpZCBjb2x1bW5zIGZvciBwbG90IGJ5IGNoYW5naW5nIGxldmVscwphbHBoYS5jb3VudHJ5LmxvbmckbmFtZSA8LSBmYWN0b3IoYWxwaGEuY291bnRyeS5sb25nJG5hbWUsIGxldmVscyA9IGMoIlJpY2huZXNzIiwgIlJhcmVmaWVkIiwiU2hhbm5vbiIsICJTaW1wc29uIikpCmFscGhhLmNvdW50cnkubG9uZyR6b25lIDwtIGZhY3RvcihhbHBoYS5jb3VudHJ5Lmxvbmckem9uZSwgbGV2ZWxzID0gYygiRXh0cmVtZSIsICJUZW1wZXJhdGUiLCJTdWItdHJvcGljYWwiLCAiVHJvcGljYWwiKSkKCiMgZ3JpZCBwbG90IG9mIGRpdmVyc2l0eSBpbmRpY2VzCmRpdmVyc2l0eS5wbG90IDwtIGdncGxvdChhbHBoYS5jb3VudHJ5LmxvbmcsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeSA9IENvdW50cnksIHggPSB2YWx1ZSwgY29sb3VyID0gem9uZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHhlbmQgPSB2YWx1ZSwgeWVuZCA9IENvdW50cnkpKSArCiAgZmFjZXRfZ3JpZCh+bmFtZSwgc2NhbGVzID0gJ2ZyZWUnKSArCiAgbGFicyh4ID0gJycsIHk9JycpICsKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZSgiTGF0LiB6b25lIikgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUoIkxhdC4gem9uZSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ251bGwnLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIHZqdXN0ID0gMCkpCgojIyMjIyMjIwoKIyBjYWxjdWxhdGUgcmljaG5lc3MgJiBhbHBoYSBkaXZlcnNpdHkgbWV0cmljcyBmb3IgbGF0aXR1ZGUgem9uZXMKYWxwaGEuZGl2ZXJzaXR5LnpvbmVzIDwtIGRhdGEuZnJhbWUoWm9uZT1yb3duYW1lcyhBcmFuZWFlLnpvbmUuYmlucykpICU+JQogICMgYmluZCBhIG5ldyBjb2x1bW4gZm9yIGVhY2ggc3RhdGlzdGljCiAgYmluZF9jb2xzKAogICAgbGlzdCgKICAgICAgYFJhbmdlIChhYnMuIGRlZylgID0gcmV2KGMoJzAtMjAnLCAnMjAtNDAnLCc0MC02MCcsICc2MCsnKSksCiAgICAgIG4gPSByb3dTdW1zKEFyYW5lYWUuem9uZS5iaW5zKSwKICAgICAgUmljaG5lc3MgPSByb3dTdW1zKEFyYW5lYWUuem9uZS5iaW5zID4gMCksCiAgICAgIGBSYXJlZmllZGAgPSB2ZWdhbjo6cmFyZWZ5KEFyYW5lYWUuem9uZS5iaW5zLCBzYW1wbGUgPSA1MDApLAogICAgICBTaGFubm9uID0gdmVnYW46OmRpdmVyc2l0eShBcmFuZWFlLnpvbmUuYmlucywgaW5kZXggPSAnc2hhbm5vbicpLAogICAgICBTaW1wc29uID0gdmVnYW46OmRpdmVyc2l0eShBcmFuZWFlLnpvbmUuYmlucywgaW5kZXggPSAnc2ltcHNvbicpCiAgICApCiAgKSAlPiUKICBtdXRhdGUoU2hhbm5vbiA9IHJvdW5kKFNoYW5ub24sIDIpLAogICAgICAgICBTaW1wc29uID0gcm91bmQoU2ltcHNvbiwgMiksCiAgICAgICAgIGBSYXJlZmllZGAgPSByb3VuZChgUmFyZWZpZWRgKSkKCiMjIyMjIyMKCiMgYXJyYW5naW5nIGxhYmVscyBmb3IgcGxvdCBiZWxvdyAobGV4aWNvIHNvcnQgeS1heGlzIHpvbmVzKSAgICAKYWxwaGEuZGl2ZXJzaXR5LnpvbmVzJFpvbmUgPC0gZmFjdG9yKGFscGhhLmRpdmVyc2l0eS56b25lcyRab25lLCBsZXZlbHM9cmV2KHNvcnQoYWxwaGEuZGl2ZXJzaXR5LnpvbmVzJFpvbmUpKSkKCiMgYXJyYW5naW5nIGRhdGEgdG8gbG9uZyBmb3JtIHdpdGggZGl2ZXJzaXR5IGluZGljZSArIHZhbHVlIHJvd3MgZm9yIGVhIGNvdW50cnkKYWxwaGEuem9uZXMubG9uZyA8LSBhbHBoYS5kaXZlcnNpdHkuem9uZXMgJT4lCiAgcGl2b3RfbG9uZ2VyKFJhcmVmaWVkOlNpbXBzb24pICU+JQogIGFycmFuZ2UoZGVzYyhab25lKSkgCgojIHJlYXJyYW5nZSBncmlkIHJvd3MsIGNvbHVtbnMgZm9yIHBsb3QKYWxwaGEuem9uZXMubG9uZyRab25lIDwtIGZhY3RvcihhbHBoYS56b25lcy5sb25nJFpvbmUsIGxldmVscyA9IGMoIkV4dHJlbWUiLCAiVGVtcGVyYXRlIiwiU3ViLXRyb3BpY2FsIiwgIlRyb3BpY2FsIikpCgphbHBoYS56b25lcy5sb25nJG5hbWUgPC0gZmFjdG9yKGFscGhhLnpvbmVzLmxvbmckbmFtZSwgbGV2ZWxzID0gYygiUmljaG5lc3MiLCAiUmFyZWZpZWQiLCJTaGFubm9uIiwgIlNpbXBzb24iKSkKCgojIGdyaWQgcGxvdCBvZiBkaXZlcnNpdHkgaW5kaWNlcwpkaXZlcnNpdHkucGxvdC56b25lIDwtIGdncGxvdChhbHBoYS56b25lcy5sb25nLGFlcyh5ID0gWm9uZSwgeCA9IHZhbHVlLCBmaWxsID0gWm9uZSkpICsKICBnZW9tX2NvbCgpICsKICAjIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHhlbmQgPSB2YWx1ZSwgeWVuZCA9IFpvbmUpKSArCiAgZmFjZXRfZ3JpZCh+bmFtZSwgc2NhbGVzID0gJ2ZyZWUnKSArCiAgbGFicyh4ID0gJycsIHk9JycpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJMYXQuIHpvbmUiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICAKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICdudWxsJykKCiMjIyMjIyMjIwoKYWxwaGEuem9uZXMuY291bnRyaWVzLnBsb3QgPC0gYWxwaGEuY291bnRyeS5sb25nICU+JQogIGdncGxvdChhZXMoeT16b25lLCB4ID0gdmFsdWUsIGNvbG91ciA9IHpvbmUpKSArCiAgZ2VvbV9ib3hwbG90KGNvbG91ciA9ICdncmF5ODAnLG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21faml0dGVyKGFscGhhID0gMC45LCBwY2ggPSAwKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiTGF0LiB6b25lIikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFscGhhLnpvbmVzLmxvbmcsIGFlcyh5PVpvbmUsIHggPSB2YWx1ZSwgY29sb3VyID0gWm9uZSksIHNpemUgPSAyKSArCiAgZmFjZXRfZ3JpZCh+bmFtZSwgc2NhbGVzPSdmcmVlJykgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKCJMYXQuIHpvbmUiKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiTGF0LiB6b25lIikgKwogIGxhYnMoeD0nJywgeT0nJykgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnbnVsbCcsCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgdmp1c3QgPSAwKSkKCgpgYGAKICAKCioqVGFibGUgMi4qKiBSaWNobmVzcyBhbmQgZGl2ZXJzaXR5IG9mIHRoZSBCT0xEIHNwaWRlciBjb2xsZWN0aW9uIGluIGRpZmZlcmVudCBsYXRpdHVkZSB6b25lcyAoYmFzZWQgb24gYWJzb2x1dGUgZGlzdGFuY2UgZnJvbSB0aGUgZXF1YXRvcikuICAKICAgICAgCgpgYGB7ciB0YWJsZS5hbHBoYSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0Ka2FibGUoYWxwaGEuZGl2ZXJzaXR5LnpvbmVzLCBmb3JtYXQgPSAncGlwZScpCmBgYAoKLS0tLQoKYGBge3IgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9NCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0KcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKGFscGhhLnpvbmVzLmNvdW50cmllcy5wbG90L2RpdmVyc2l0eS5wbG90KQpgYGAKICAKKipGaWd1cmUgNC4qKiBSYXJlZmllZCByaWNobmVzcyAobj01MDApLCBTaGFubm9uIGRpdmVyc2l0eSwgYW5kIFNpbXBzb24gZGl2ZXJzaXR5IG9mIHNwaWRlciBzcGlkZXIgY29tbXVuaXRpZXMgaW4gbGF0aXR1ZGUgem9uZXMgKHRvcCkgYW5kIGNvdW50cmllcyAoYm90dG9tKS4gQ291bnRyaWVzIHdlcmUgYXNzaWduZWQgdG8gem9uZXMgYmFzZWQgb24gdGhlaXIgbWVhbiBzcGVjaW1lbiBsYXRpdHVkZS4gKnRvcCo6IEluIGVhY2ggcGFuZWwsIHRoZSB2YWx1ZXMgZm9yIGVhY2ggY291bnRyeSBpbiB0aGUgem9uZSBhcmUgc2hvd24gYXMgaG9sbG93IHNxdWFyZXMsIHdpdGggdGhlIGRpc3RyaWJ1dGlvbiBzaG93biBieSB0aGUgYm94cGxvdDsgdGhlIHZhbHVlcyBmb3IgdGhlIHpvbmUgY29tbXVuaXRpZXMgc2hvd24gYXMgc29saWQgY2lyY2xlcy4gKmJvdHRvbSo6IHRoZSBpbmRleCB2YWx1ZSBpcyBzaG93biBmb3IgZWFjaCBjb3VudHJ5LCBsb2xsaXBvcHMgYXJlIGNvbG9yZWQgYnkgdGhlIGxhdGl0dWRlIHpvbmUgdGhlIGNvdW50cnkgd2FzIGFzc2lnbmVkIHRvLiAKICAKICAKCgoKIyMjIFJhcmVmYWN0aW9uICYgU3BlY2llcyBBYnVuZGFuY2UgQ3VydmVzCgpSYXJlZmFjdGlvbiB3ZXJlIGNvbXB1dGVkIHVzaW5nIHRoZSB2ZWdhbjo6cmFyZWN1cnZlIGZ1bmN0aW9uIGZvciBzcGVjaW1lbnMgZ3JvdXBlZCBieSBlYWNoIG9mIGNvdW50cnkgYW5kIGxhdGl0dWRlIHpvbmUuCgoKYGBge3IgcmFyZWZhY3Rpb24uY29tcHV0YXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUV9CiMgIyBmdWxsIGRhdGEgcmFyZWZhY3Rpb24KIyBBcmFuZWFlLnJhciA8LSByYXJlY3VydmUoQXJhbmVhZS5kZi5iaW5zLCkKIyBBcmFuZWFlLnJhciA8LSB0aWJibGUoeSA9IEFyYW5lYWUucmFyW1sxXV0pICU+JQojICAgbXV0YXRlKHg9cm93X251bWJlcigpKQojIHdyaXRlX3JkcyhBcmFuZWFlLnJhciwgIi4vZGF0YS9BcmFuZWFlLnJhcmVmYWN0aW9uLnJkcyIpCiMgCiMgIyMgcmFyZWZhY3Rpb24gY3VydmVzIGJ5IGxhdCB6b25lCiMgQXJhbmVhZS56b25lLnJhciA8LSByYXJlY3VydmUoQXJhbmVhZS56b25lLmJpbnMpCiMgCiMgIyBtYW5pcHVsYXRlIGxpc3Qgb3V0cHV0IGZyb20gdmVnYW4gYmFjayBpbnRvIHRpZHkgZGF0YQojIEFyYW5lYWUuem9uZS5yYXIgPC0gdGliYmxlKHpvbmUgPSByb3duYW1lcyhBcmFuZWFlLnpvbmUuYmlucyksCiMgICAgICAgIGxpc3QgPSBBcmFuZWFlLnpvbmUucmFyKSAlPiUKIyAgICMgc3ByZWFkIGxpc3QgaW50byBpbmRpdmlkdWFsIGNvbHVtbnMKIyAgIHVubmVzdF93aWRlcihjb2wgPSBsaXN0KSAlPiUKIyAgICMgZ2V0IGxvbmcgZm9ybSB0YWJsZQojICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtem9uZSkgJT4lCiMgICAjIHJlbW92ZSByb3dzIG1pc3NpbmcgdmFsdWUgJiB1c2VsZXNzIG5hbWVzIGNvbHVtbgojICAgZmlsdGVyKCFpcy5uYSh2YWx1ZSkpICU+JQojICAgc2VsZWN0KC1uYW1lKSAlPiUKIyAgICMgY3JlYXRlIHZlY3RvciBmb3Igc2FtcGxpbmcgZGVwdGgKIyAgIGdyb3VwX2J5KHpvbmUpICU+JQojICAgbXV0YXRlKHNhbXBsZV9zaXplID0gcm93X251bWJlcigpKQojIHdyaXRlX3JkcyhBcmFuZWFlLnpvbmUucmFyLCAiLi9kYXRhL0FyYW5lYWUuem9uZXMucmFyZWZhY3Rpb24ucmRzIikKIyAKIyAjIyByYXJlZmFjdGlvbiBjdXJ2ZXMgYnkgY291bnRyeQojIEFyYW5lYWUuY291bnRyeS5yYXIgPC0gcmFyZWN1cnZlKEFyYW5lYWUuY291bnRyeS5iaW5zKQojIAojICMgbWFuaXB1bGF0ZSBsaXN0IG91dHB1dCBmcm9tIHZlZ2FuIGJhY2sgaW50byB0aWR5IGRhdGEKIyBBcmFuZWFlLmNvdW50cnkucmFyIDwtIHRpYmJsZShDb3VudHJ5ID0gcm93bmFtZXMoQXJhbmVhZS5jb3VudHJ5LmJpbnMpLAojICAgICAgICBsaXN0ID0gQXJhbmVhZS5jb3VudHJ5LnJhcikgJT4lCiMgICB1bm5lc3Rfd2lkZXIoY29sID0gbGlzdCkgJT4lCiMgICBwaXZvdF9sb25nZXIoY29scyA9IC1Db3VudHJ5KSAlPiUKIyAgIGZpbHRlcighaXMubmEodmFsdWUpKSAlPiUKIyAgIHNlbGVjdCgtbmFtZSkgJT4lCiMgICBncm91cF9ieShDb3VudHJ5KSAlPiUKIyAgIG11dGF0ZShzYW1wbGVfc2l6ZSA9IHJvd19udW1iZXIoKSkKIyB3cml0ZV9yZHMoQXJhbmVhZS5jb3VudHJ5LnJhciwgIi4vZGF0YS9BcmFuZWFlLmNvdW50cnkucmFyZWZhY3Rpb24ucmRzIikKYGBgCgoKU3BlY2llcyBhY2N1bXVsYXRpb24gY3VydmVzIHdlcmUgY29tcHV0ZWQgdXNpbmcgdGhlIHZlZ2FuOjpzcGVjYWNjdW0gZnVuY3Rpb24gZm9yIHNwZWNpbWVucyBncm91cGVkIGJ5IGVhY2ggb2YgY291bnRyeSBhbmQgbGF0aXR1ZGUgem9uZS4KCmBgYHtyIHNwZWNhY2N1bS5jb21wdXRhdGlvbiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0KIyAjIyBTcGVjaWVzIGFjY3VtdWxhdGlvbiBjdXJ2ZXMKIyAjIHNwZWNhY2N1bSBieSBjb3VudHJ5CiMgU3BlY2FjY3VtLmNvdW50cnkgPC0gc3BlY2FjY3VtKEFyYW5lYWUuY291bnRyeS5iaW5zKQojIFNwZWNhY2N1bS5jb3VudHJ5IDwtIHRpYmJsZSgKIyAgIHNpdGVzID0gU3BlY2FjY3VtLmNvdW50cnlbJ3NpdGVzJ10sCiMgICByaWNobmVzcyA9IFNwZWNhY2N1bS5jb3VudHJ5WydyaWNobmVzcyddLAojICAgc2QgPSBTcGVjYWNjdW0uY291bnRyeVsnc2QnXSwKIyAgICkgJT4lCiMgICB1bm5lc3QoY29scyA9IGMoc2l0ZXMsIHJpY2huZXNzLCBzZCkpICU+JQojICAgbXV0YXRlKHNkMSA9IGlmZWxzZShyaWNobmVzcy1zZD49MCwgcmljaG5lc3Mtc2QsIDApLAojICAgICAgICAgIHNkMiA9IHJpY2huZXNzK3NkKQojIHdyaXRlX3JkcyhTcGVjYWNjdW0uY291bnRyeSwgIlNwZWNhY2N1bS5jb3VudHJ5LnJkcyIpCiMgCiMgIyBzcGVjYWNjdW0gYnkgem9uZQojIFNwZWNhY2N1bS56b25lIDwtIHNwZWNhY2N1bShBcmFuZWFlLnpvbmUuYmlucykKIyBTcGVjYWNjdW0uem9uZSA8LSB0aWJibGUoCiMgICBzaXRlcyA9IFNwZWNhY2N1bS56b25lWydzaXRlcyddLAojICAgcmljaG5lc3MgPSBTcGVjYWNjdW0uem9uZVsncmljaG5lc3MnXSwKIyAgIHNkID0gU3BlY2FjY3VtLnpvbmVbJ3NkJ10sCiMgICApICU+JQojICAgdW5uZXN0KGNvbHMgPSBjKHNpdGVzLCByaWNobmVzcywgc2QpKSAlPiUKIyAgIG11dGF0ZShzZDEgPSBpZmVsc2UocmljaG5lc3Mtc2Q+PTAsIHJpY2huZXNzLXNkLCAwKSwKIyAgICAgICAgICBzZDIgPSByaWNobmVzcytzZCkKIyB3cml0ZV9yZHMoU3BlY2FjY3VtLnpvbmUsICIuL2RhdGEvU3BlY2FjY3VtLnpvbmUucmRzIikKCmBgYAoKUGxvdHMgd2VyZSBjcmVhdGVkIGZvciB0aGUgcmFyZWZhY3Rpb24gYW5kIHNwZWNpZXMgYWNjdW11bGF0aW9uIGN1cnZlcyBpbiB0aGUgZm9sbG93aW5nIGNvZGU6CgpgYGB7ciBlY29sLmFuYWx5c2lzLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIyBSQVJFRkFDVElPTgojIHJlYWQgaW4gcmFyLiBjdXJ2ZSBkYXRhIGNvbXB1dGVkIGFib3ZlCkFyYW5lYWUucmFyIDwtIHJlYWRfcmRzKCIuL2RhdGEvQXJhbmVhZS5yYXJlZmFjdGlvbi5yZHMiKQpBcmFuZWFlLnpvbmUucmFyIDwtIHJlYWRfcmRzKCIuL2RhdGEvQXJhbmVhZS56b25lcy5yYXJlZmFjdGlvbi5yZHMiKQpBcmFuZWFlLmNvdW50cnkucmFyIDwtIHJlYWRfcmRzKCIuL2RhdGEvQXJhbmVhZS5jb3VudHJ5LnJhcmVmYWN0aW9uLnJkcyIpCgojIHJhcmVmYWN0aW9uIHBsb3QgZm9yIGVudGlyZSBkYXRhc2V0CnBsb3QucmFyLmZ1bGwgPC0gQXJhbmVhZS5yYXIgJT4lCiAgZ2dwbG90KGFlcyh4PXgvMTAwMCwgeT15KSkgKwogIGdlb21fbGluZSgpICsKICBsYWJzKHkgPSAnVW5pcXVlIEJJTnMnLCB4ID0gJ1NhbXBsZSBzaXplIChrKScpICsKICB0aGVtZV9jbGFzc2ljKCkKCiMgcmFyZWZhY3Rpb24gY3VydmVzIGZvciBsYXRpdHVkZSB6b25lcwpwbG90LnJhci56b25lIDwtIGdncGxvdChBcmFuZWFlLnpvbmUucmFyLAogICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1zYW1wbGVfc2l6ZS8xMDAwLCB5ID0gdmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IHpvbmUsIGNvbG91ciA9IHpvbmUpKSArCiAgZ2VvbV9saW5lKGFscGhhID0gMC43KSArCiAgc2NhbGVfY29sb3VyX2Rpc2NyZXRlKCdMYXQuIHpvbmUnKSArCiAgbGFicyh4ID0gJ1NhbXBsZSBzaXplIChrKScsIHkgPSAnVW5pcXVlIEJJTnMnKSArCiAgdGhlbWVfY2xhc3NpYygpCgojIGFkZGVkIGxhdCB6b25lIGxhYmVscyB0byBjb3VudHJ5IHJhcmVmYWN0aW9uIGN1cnZlcyBkYXRhIGZvciBwbG90CkFyYW5lYWUuY291bnRyeS5yYXIgPC0gbGVmdF9qb2luKEFyYW5lYWUuY291bnRyeS5yYXIsIGNvdW50cnlfem9uZXMsIGJ5ID0gJ0NvdW50cnknKQoKIyBwbG90IHJhcmVmYWN0aW9uIGN1cnZlcyBmb3IgZWFjaCBjb3VudHJ5LCBjb2xvdXIgYnkgem9uZQpwbG90LnJhci5jb3VudHJ5IDwtCiAgQXJhbmVhZS5jb3VudHJ5LnJhciAlPiUKICBmaWx0ZXIoIWlzLm5hKHpvbmUpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2FtcGxlX3NpemUvMTAwMCwgeSA9IHZhbHVlKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBDb3VudHJ5LCBjb2xvdXIgPSB6b25lKSwgYWxwaGEgPSAwLjcpICsKICAjIGFkZCBsYWJlbHMgZm9yIDEwIG1vc3Qtc2FtcGxlZCBjb3VudHJpZXMKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGNvdW50cnkuc3BlY2ltZW5zLnRhYmxlWzE6MTAsXSwKICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IGNvdW50cnksIHggPSBzcGVjaW1lbnMvMTAwMCwgeSA9IHNwZWNpZXMpLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAsIHNpemUgPSAzLAogICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSArCiAgc2NhbGVfY29sb3VyX2Rpc2NyZXRlKCdMYXQuIHpvbmUnKSArCiAgbGFicyh4ID0gJ1NhbXBsZSBzaXplIChrKScsIHkgPSAnVW5pcXVlIEJJTnMnKSArCiAgdGhlbWVfY2xhc3NpYygpCgpwbG90LnJhci5jb3VudHJ5MiA8LSAKICBBcmFuZWFlLmNvdW50cnkucmFyICU+JQogIGZpbHRlcighaXMubmEoem9uZSkpICU+JQogIGdncGxvdChhZXMoeD1zYW1wbGVfc2l6ZSwgeSA9IHZhbHVlKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBDb3VudHJ5LCBjb2xvdXIgPSB6b25lKSwgYWxwaGEgPSAwLjcpICsKICAjIGFkZCBsYWJlbHMgZm9yIDEwIG1vc3Qtc2FtcGxlZCBjb3VudHJpZXMKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGNvdW50cnkuc3BlY2ltZW5zLnRhYmxlWzE6MTAsXSwKICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IGNvdW50cnksIHggPSBzcGVjaW1lbnMsIHkgPSBzcGVjaWVzKSwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAwLCBzaXplID0gMywKICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkgKwogIHNjYWxlX2NvbG91cl9kaXNjcmV0ZSgnTGF0LiB6b25lJykgKwogIGxhYnMoeCA9ICdTYW1wbGUgc2l6ZScsIHkgPSAnVW5pcXVlIEJJTnMnKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB4bGltKGMoMCwgNTAwKSkgKwogIHlsaW0oYygwLCAzNDApKQoKCiMjIFNQRUNJRVMgQUNDVU1VTEFUSU9OClNwZWNhY2N1bS5jb3VudHJ5IDwtIHJlYWRfcmRzKCIuL2RhdGEvU3BlY2FjY3VtLmNvdW50cnkucmRzIikKU3BlY2FjY3VtLnpvbmUgPC0gcmVhZF9yZHMoIi4vZGF0YS9TcGVjYWNjdW0uem9uZS5yZHMiKQoKIyBwbG90IHNwZWNpZXMgYWNjdW11bGF0aW9uIGJ5IGNvdW50cnkKcGxvdC5TcGVjYWNjdW0uY291bnRyeSA8LSAgZ2dwbG90KFNwZWNhY2N1bS5jb3VudHJ5KSArCiAgZ2VvbV9yaWJib24oYWVzKHg9c2l0ZXMsIHk9cmljaG5lc3MsIHltaW4gPSBzZDEsIHltYXggPSBzZDIpLAogICAgICAgICAgICAgIGZpbGwgPSAnY29ybmZsb3dlcmJsdWUnLCBhbHBoYSA9IDAuMykgKwogIGdlb21fbGluZShhZXMoeCA9IHNpdGVzLCB5ID0gcmljaG5lc3MpLAogICAgICAgICAgICBzaXplID0gMS4zLCBjb2xvdXIgPSAnYmx1ZTQnLCBhbHBoYSA9IDAuNykgKwogIGxhYnMoeSA9ICdCSU4gUmljaG5lc3MnLCB4ID0gJ0NvdW50cmllcycpICsKICB0aGVtZV9jbGFzc2ljKCkKCiMgcGxvdCBzcGVjaWVzIGFjY3VtdWxhdGlvbiBieSBsYXRpdHVkZSB6b25lCnBsb3QuU3BlY2FjY3VtLnpvbmUgPC0gIGdncGxvdChTcGVjYWNjdW0uem9uZSkgKwogIGdlb21fcmliYm9uKGFlcyh4PXNpdGVzLCB5PXJpY2huZXNzLCB5bWluID0gc2QxLCB5bWF4ID0gc2QyKSwKICAgICAgICAgICAgICBmaWxsID0gJ3JlZCcsIGFscGhhID0gMC4yKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gc2l0ZXMsIHkgPSByaWNobmVzcyksCiAgICAgICAgICAgIHNpemUgPSAxLjMsIGNvbG91ciA9ICdyZWQzJywgYWxwaGEgPSAwLjcpICsKICBsYWJzKHkgPSAnQklOIFJpY2huZXNzJywgeCA9ICdMYXRpdHVkZSB6b25lcycpICsKICB0aGVtZV9jbGFzc2ljKCkKCiMjIGNyZWF0ZSByYXJlZmFjdGlvbi9zcGVjYWNjdW0gcGxvdHMgZmlndXJlCgpgYGAKCiAgIApgYGB7ciBzaG93LnJhcmVmYWN0aW9uLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIHNob3cgcmFyZWZhY3Rpb24gcGxvdHMgcGFuZWwgd2l0aCBwYXRjaHdvcms6OgoocGxvdC5yYXIuZnVsbCArIHBsb3QucmFyLnpvbmUpIC8gCiAgKHBsb3QucmFyLmNvdW50cnkgKyBwbG90LnJhci5jb3VudHJ5MikgLwogIChwbG90LlNwZWNhY2N1bS5jb3VudHJ5ICsgcGxvdC5TcGVjYWNjdW0uem9uZSkgKwogIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gJ0EnKSArCiAgcGxvdF9sYXlvdXQoZ3VpZGVzID0gJ2NvbGxlY3QnKSAmIAogIHRoZW1lKHBsb3QudGFnLnBvc2l0aW9uID0gYygwLCAxKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogICAgICAgIHBsb3QudGFnID0gZWxlbWVudF90ZXh0KHNpemUgPSA4LCBoanVzdCA9IDAsIHZqdXN0ID0gMCkpCmBgYAogICAgCioqRmlndXJlIDMuIEEtRDoqKiBSYXJlZmFjdGlvbiBjdXJ2ZXMgZm9yIGVudGlyZSBjb2xsZWN0aW9uIG9mIEJPTEQgc3BpZGVyIHNwZWNpbWVucyAoQSksIGJ5IGxhdGl0dWRlIHpvbmUgKEIpLCBhbmQgYnkgc291cmNlIGNvdW50cnkgKEMpLiBCZWNhdXNlIG9mIHRoZSBkaXNjcmVwZW5jeSBpbiBzYW1wbGluZywgYSBjbG9zZS11cCBvZiB0aGUgY291bnRyaWVzJyByYXJlZmFjdGlvbiBjdXJ2ZXMgYXJlIHNob3duIGZvciBzbWFsbGVyIHNhbXBsZSBzaXplcyAoRCkuIEN1cnZlcyBhcmUgY29sb3VyZWQgYnkgbGF0aXR1ZGUgem9uZSB3aGVyZSBhcHBsaWNhYmxlLiBDb3VudHJpZXMgYXJlIGFzc2lnbmVkIHRvIGxhdGl0dWRlIHpvbmVzIGJ5IHRoZSBtZWFuIGxhdGl0dWRlIG9mIGFsbCB0aGVpciBzYW1wbGVzLiAgUmFyZWZhY3Rpb24gY3VydmVzIHdlcmUgY29tcHV0ZWQgdXNpbmcgdGhlIGB2ZWdhbjo6cmFyZWN1cnZlYCBmdW5jdGlvbi4gICoqRUY6KiogU3BlY2llcyBhY2N1bXVsYXRpb24gY3VydmVzIHdlcmUgY29tcHV0ZWQgdXNpbmcgdGhlIHZlZ2FuOjpzcGVjYWNjdW0gZnVuY3Rpb24gZm9yIHNwZWNpbWVucyBncm91cGVkIGJ5IGVhY2ggb2YgY291bnRyeSAoRSkgYW5kIGxhdGl0dWRlIHpvbmUgKEYpOyBsaW5lcyBzaG93IHJpY2huZXNzICsvLSBzZC4KCgojIyMgT3JkaW5hdGlvbiBieSBOTURTIGFuZCBzcGVjaWVzIG5ldHdvcmsgYW5heWxzaXMKCmBgYHtyIG5tZHMucGxvdCwgZmlnLmhlaWdodD00LCBmaWcuc2hvdz0naG9sZCcsIGZpZy53aWR0aD01LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIE5NRFMKem9uZS5ubWRzIDwtIG1ldGFNRFMoQXJhbmVhZS56b25lLmJpbnMsIGRpc3RhbmNlID0gJ2JyYXknLCB0cmFjZSA9IEZBTFNFKQojIHpvbmUubm1kcwpwYXIobWFyPWMoNSw0LDEsMSkpCnBsb3Qoem9uZS5ubWRzLCBhbHBoYT0wLjUsIGNleCA9IDAuNykKdGV4dCh6b25lLm5tZHMsIGRpc3BsYXkgPSAnc2l0ZXMnLCBjZXggPSAwLjkpCmBgYAogICAgCioqRmlndXJlIDUuKiogTk1EUyBvZiBzcGlkZXIgQklOIGFidW5kYW5jZXMgaW4gZm91ciBsYXRpdHVkZSB6b25lcyB1c2luZyBCcmF5IGRpc3RhbmNlIGFuZCBXaXNjb25zaW4gc3RhbmRhcmRpemF0aW9uIG9mIHNxdWFyZS1yb290LXRyYW5zZm9ybWVkIGFidW5kYW5jZXMuCgoKICAKYGBge3IgbmV0d29yaywgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIyBOZXR3b3JrIHBsb3Qgd2l0aCBzaGFyZWQgQklOcyBiZXR3ZWVuIHpvbmVzCkFyYW5lYWUuem9uZS5iaW5zIDwtIHJlYWRfcmRzKCIuL2RhdGEvQXJhbmVhZS56b25lLmJpbnMucmRzIikKIyBtYWtlIGFuIGVkZ2VsaXN0IGZvciBzaW1wbGUgZ3JhcGggKGZvciBiaW5zIHNoYXJlZCBiZXR3ZWVuIHpvbmVzKQplZGdlbGlzdCA8LSB0aWJibGUoCiAgdSA9IGMocm93bmFtZXMoQXJhbmVhZS56b25lLmJpbnMpKSwKICB2ID0gcmVwKGxpc3Qocm93bmFtZXMoQXJhbmVhZS56b25lLmJpbnMpKSw0KQopICU+JQogIHVubmVzdCh2KSAlPiUKICBmaWx0ZXIoIXU9PXYpCgoKIyBnZXQgcmlkIG9mIGR1cGxpY2F0ZSBlZGdlcyBpbiBlZGdlbGlzdCAoc2luY2UgZ3JhcGggaXMgbm90IGRpcmVjdGlvbmFsKQplZGdlLnN0cmluZ3MgPC0gIHN0cl9zcGxpdChwYXN0ZShlZGdlbGlzdCR1LCBlZGdlbGlzdCR2KSwgJyAnKQojIHNvcnQgZWRnZXMgdG8gcmVtb3ZlIGRpcmVjdGlvbmFsaXR5CmVkZ2VsaXN0IDwtIHVuaXF1ZShsYXBwbHkoZWRnZS5zdHJpbmdzLCBmdW5jdGlvbih4KSB1bmlxdWUoc29ydCh4KSkpKQojIHJlbW92ZSBzZWxmLXNlbGYgZWRnZXMKZWRnZWxpc3QgPC0gZWRnZWxpc3Rbd2hpY2gobGVuZ3RocyhlZGdlbGlzdCk+MSldCiMgcGFzdGUgdSB2IHZlcnRpY2VzIGZvciBlYWNoIGVkZ2UgdG8gZmlsdGVyIGJpbnMuZWRnZWxpc3QgbGF0ZXIgKGJlbG93KQplZGdlbGlzdCA8LSBsYXBwbHkoZWRnZWxpc3QsIGZ1bmN0aW9uKHgpIHBhc3RlMCh4LCBjb2xsYXBzZSA9ICcgJykpCnJtKGVkZ2Uuc3RyaW5ncykKCiMgR2V0IGxpc3Qgb2YgdW5pcXVlIGJpbnMgZm9yIGVhY2ggem9uZSBmcm9tIHpvbmUgYWJ1bmQuIG1hdHJpeAp6b25lLmJpbnMubGlzdCA8LSB0aWJibGUoQXJhbmVhZS56b25lLmJpbnMpICU+JQogIG11dGF0ZSh6b25lID0gcm93bmFtZXMoQXJhbmVhZS56b25lLmJpbnMpKSAlPiUKICBwaXZvdF9sb25nZXIoLXpvbmUpICU+JQogIGZpbHRlcighdmFsdWUgPT0gMCkgJT4lCiAgZ3JvdXBfYnkoem9uZSkgJT4lCiAgbXV0YXRlKGJpbnMgPSBsaXN0KG5hbWUpKSAlPiUKICBzZWxlY3QoLWModmFsdWUsIG5hbWUpKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIG11dGF0ZSh1bmlxdWVzID0gdW5pcXVlKGJpbnMpKSAKCgojIENyZWF0ZSBtYXRyaXggd2l0aCBzaXplcyBvZiBpbnRlcnNlY3Qgb2YgdW5pcXVlIGJpbnMgYmV0d2VlbiB6b25lcy4gRWFjaCBjb2wgaGFzIHRoZSBzaXplIG9mIHRoZSBpbnRlcnNlY3Rpb24gYmV0d2VlbiBhIHpvbmUgYW5kIGVhY2ggem9uZSAoc2VsZi1zZWxmIGlzIG9uIGRpYWdvbmFsKSAtIGZvciBuZXR3b3JrIGVkZ2Ugd2VpZ2h0cwpiaW5zLmxzIDwtIHpvbmUuYmlucy5saXN0ICU+JQogIHNlbGVjdCh6b25lLCBiaW5zKSAlPiUKICBtdXRhdGUoRXh0cmVtZSA9IGxlbmd0aChpbnRlcnNlY3Qoem9uZS5iaW5zLmxpc3RbMSwgM11bWzFdXVtbMV1dLCBiaW5zW1sxXV0pKSwKICAgICAgICAgVGVtcGVyYXRlID0gbGVuZ3RoKGludGVyc2VjdCh6b25lLmJpbnMubGlzdFsyLCAzXVtbMV1dW1sxXV0sIGJpbnNbWzFdXSkpLAogICAgICAgICBgU3ViLXRyb3BpY2FsYCA9IGxlbmd0aChpbnRlcnNlY3Qoem9uZS5iaW5zLmxpc3RbMywgM11bWzFdXVtbMV1dLCBiaW5zW1sxXV0pKSwKICAgICAgICAgVHJvcGljYWwgPSBsZW5ndGgoaW50ZXJzZWN0KHpvbmUuYmlucy5saXN0WzQsIDNdW1sxXV1bWzFdXSwgYmluc1tbMV1dKSksCiAgKSAlPiUKICBzZWxlY3QoLWJpbnMpICU+JQogIHBpdm90X2xvbmdlcihFeHRyZW1lOlRyb3BpY2FsKSAlPiUKICByZW5hbWUoem9uZTEgPSB6b25lLAogICAgICAgICB6b25lMiA9IG5hbWUsCiAgICAgICAgIHdlaWdodCA9IHZhbHVlKQoKIyBGaWx0ZXIgd2VpZ2h0ZWQgZWRnZWxpc3QgdG8ga2VlcCBzaW5nbGUgZWRnZSBmb3IgZWFjaCBwYWlyIChub3QgYmlkaXJlY3Rpb25hbCAtIG1hZGUgJ2VkZ2VsaXN0JyBhdCB0b3Agb2YgY2h1bmspCmJpbnMuZWRnZXMgPC0gYmlucy5scyAlPiUKICBmaWx0ZXIoIXpvbmUxID09IHpvbmUyKSAlPiUKICBtdXRhdGUoZWRnZSA9IHBhc3RlKHpvbmUxLCB6b25lMikpICU+JQogIGZpbHRlcihlZGdlICVpbiUgZWRnZWxpc3QpICU+JQogIHNlbGVjdCgtZWRnZSkKCgojIHRvdGFsIG51bWJlciBvZiB1bmlxdWUgYmlucyBhdCBlYWNoIHpvbmUgLSBmb3IgdmVydGV4IHNpemUKdG90YWxfYmlucyA8LSBiaW5zLmxzICAlPiUKICBmaWx0ZXIoem9uZTEgPT0gem9uZTIpICU+JQogIHNlbGVjdCgtem9uZTIpICU+JQogIHJlbmFtZShzaXplID0gd2VpZ2h0KQoKbmV0IDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkPSBiaW5zLmVkZ2VzLCB2ZXJ0aWNlcyA9IHRvdGFsX2JpbnMsIGRpcmVjdGVkID0gRikKCiN2ZXJ0aWNlIHByb3BlcnRpZXMKVihuZXQpJGNvbG9yIDwtIGMoICdjeWFuJywgImdvbGQiLCAidG9tYXRvIiwgInBsdW0iKQpWKG5ldCkkc2l6ZSA8LSB0b3RhbF9iaW5zJHNpemUvMTAwICsgMjAKCiMgZWRnZSBwcm9wZXJ0aWVzCkUobmV0KSR3ZWlnaHQgPC0gYmlucy5lZGdlcyR3ZWlnaHQqMTAwCkUobmV0KSR3aWR0aCA8LSBzcXJ0KEUobmV0KSR3ZWlnaHQpLzIwCkUobmV0KSRlZGdlLmxhYmVsIDwtIGJpbnMuZWRnZXMkd2VpZ2h0CkUobmV0KSRlZGdlLmNvbG9yIDwtICJncmF5OTAiCkUobmV0KSRhcnJvdy5zaXplIDwtIC4wCgojIFBsb3Qgc3BlY2llcyBuZXR3b3JrCnNldC5zZWVkKDQpCnBhcihtYXI9YygxLDEsMSwxKSkKcGxvdChuZXQsIAogICAgIGxheW91dCA9IGxheW91dC5mcnVjaHRlcm1hbi5yZWluZ29sZChuZXQpLAogICAgIGxhYmVsLmRpc3QgPSAyLAogICAgIGVkZ2UubGFiZWwgPSBiaW5zLmVkZ2VzJHdlaWdodCwKICAgICBlZGdlLmxhYmVsLmNvbG9yID0ibmF2eSIsCiAgICAgZWRnZS5sYWJlbC5jZXggPSAwLjgsCiAgICAgZWRnZS5sYWJlbC5mYW1pbHkgPSAnc2FucycsCiAgICAgdmVydGV4LmxhYmVsID0gcGFzdGUwKFYobmV0KSRuYW1lLCAnXG4oJywgdG90YWxfYmlucyRzaXplLCAnKScpLAogICAgIHZlcnRleC5sYWJlbC5jb2xvcj0iYmxhY2siLAogICAgIHZlcnRleC5sYWJlbC5mYW1pbHkgPSAnc2FucycsCiAgICAgdmVydGV4LmxhYmVsLmZvbnQgPSAyLAogICAgIHZlcnRleC5sYWJlbC5jZXg9LjcsCiAgICAgdmVydGV4LmZyYW1lLmNvbG9yID0gJ3doaXRlJykKYGBgCiAgCiAgCioqRmlndXJlIDYuKiogTmV0d29yayBvZiBsYXRpdHVkZS16b25lZCBzcGlkZXIgYXNzZW1ibGFnZXMgbGlua2VkIGJ5IHNoYXJlZCBiYXJjb2RlcyBzaG93cyB0aGF0IHNpbWlsYXJpdHkgaW5jcmVhc2VzIHdpdGggbGF0aXR1ZGUuIFZlcnRpY2VzIHJlcHJlc2VudCBsYXRpdHVkZSB6b25lIGFuZCBCSU4gcmljaG5lc3M7IGVkZ2VzIGFyZSB3aWVnaHRlZCBieSB0aGUgbnVtYmVyIG9mIHNoYXJlZCBCSU5zIGJldHdlZW4gem9uZXMuCiAgIAoKLS0tLQoKCiMgRGlzY3Vzc2lvbgoKPCEtLSAjIHN1bW1hcml6ZSAtLT4KCkluIHRoaXMgd29yayBJIGV4YW1pbmVkIHRoZSBsYXRpdHVkaW5hbCBkaXZlcnNpdHkgZ3JhZGllbnQgaW4gRE5BLWJhcmNvZGVkIHNwaWRlciBzcGVjaW1lbnMgcmVjb3JkZWQgaW4gQk9MRDsgYXMgd2VsbCBhcyB0byBldmFsdWF0ZSBnZW9ncmFwaGljYWwgc2FtcGxpbmcgYmlhcyBpbiB0aGlzIGNvbGxlY3Rpb24uIFRvIHRoaXMgZW5kLCBhIG51bWJlciBvZiBlY29sb2dpY2FsIGFuYWx5c2lzIHdlcmUgcGVyZm9ybWVkIGluY2x1ZGluZyByYXJlZmFjdGlvbiwgc3BlY2llcyBhY2N1bXVsYXRpb24sIGFuZCBvcmRpbmF0aW9uLiBUaGUgQmFyY29kZSBvZiBMaWZlIGRhdGFiYXNlIChCT0xEKSBjb250YWlucyBhIGh1Z2UgbnVtYmVyIG9mIHNwaWRlciBzcGVjaW1lbiByZWNvcmRzICgxMjRrKSBhbmQgYXNzb2NpYXRlZCBETkEtYmFyY29kZSBzZXF1ZW5jZXMgKDEwNms7IHRhYmxlIDEpIFtAUmF0bmFzaW5naGFtMjAwNzsgQFJhdG5hc2luZ2hhbTIwMTNdLiBUaGVyZSBpcyBhIHN1cnByaXNpbmdseSBsYXJnZSBudW1iZXIgb2YgdW5pcXVlIEROQSBiYXJjb2RlIGluZGVudGlmaWVycyAoQklOcykgY29tcGFyZWQgdG8gc3BlY2llcyBuYW1lcyAoOSw4NDUgKnZzKiAzLDgyMikuIEFkZGl0aW9uYWxseSBsYXJnZSBudW1iZXIgb2Ygc3BlY2ltZW5zIGFyZSBtaXNzaW5nIHRheG9ub21pYyBsYWJlbHMgYXQgdGhlIGZhbWlseSwgZ2VudXMsIGFuZCBzcGVjaWVzIGxldmVscyAoMTdrLCAyMWssIGFuZCAyM2sgcmVjb3JkcywgcmVzcGVjdGl2ZWx5KSwgaW5kaWNhdGluZyB0aGF0IGJhcmNvZGUtYmFzZWQgYW5hbHlzaXMgaXMgZXNwZWNpYWxseSB1c2VmdWwgZm9yIHNwaWRlcnMuIE1vc3QgYmFyY29kZXMgaGF2ZSBvbmx5IGEgZmV3IHNwZWNpbWVucywgYW5kIHRoZSBudW1iZXIgb2Ygc3BlY2ltZW5zIHBlciBiYXJjb2RlIHNlcXVlbmNlIGhhcyBhIG5lZ2F0aXZlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiAoZmlnLiAyIHJpZ2h0KQoKPCEtLSBnbG9iYWwgc2FtcGxpbmcgZWZmb3J0IC0tPgpUbyBldmFsdWF0ZSB0aGUgZ2xvYmFsIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc2FtcGxpbmcgZWZmb3J0IHJlcHJlc2VudGVkIGluIHRoZSBCT0xEIHNwaWRlciBjb2xsZWN0aW9uLCBhbGwgcmVjb3JkcyBoYXZpbmcgYmFyY29kZXMgYW5kIGdlb2RhdGEgKDk2aykgd2VyZSBiaW5uZWQgaW50byBhIDEgZGVnIGdyaWQgYW5kIG1hcHBlZCAoZmlnLiAxKS4gU3Ryb25nIE5vcnRoIEFtZXJpY2FuIGFuZCBFdXJvcGVhbiBzYW1wbGluZyBiaWFzIGlzIGV2aWRlbnQ7IHZhc3Qgc3dhdGhzIG9mIEFmcmljYSBhbmQgQ2VudHJhbCBBc2lhIGhhdmUgbm8gcmVwcmVzZW50YXRpdmVzLiBUaGUgc2FtcGxpbmcgb2Ygc3BpZGVyIHNwZWNpbWVucyBpcyBoZWF2aWx5IHNrZXdlZCB0byBub3J0aGVybiBsYXRpdHVkZXMgKGZpZy4gMiBsZWZ0KSB0aG91Z2ggdGhpcyBpcyByb3VnaGx5IHByb3BvcnRpb25hbCB0byBvdmVyYWxsIGxhbmRtYXNzLiBXaGlsZSB0aGVyZSBhcmUgYSBsYXJnZSBudW1iZXIgb2Ygc3BpZGVyIGZhbWlsaWVzIHJlcHJlc2VudGVkIGluIHRoZSBkYXRhc2V0LCBhIGZldyBmYW1pbGllcyAoKkxpbnlwaGlpZGFlKiwgKkx5Y29zaWRhZSogYW5kICpBcmFuZWlkYWUqKSB0ZW5kIHRvIGRvbWluYXRlIGNvbW11bml0aWVzIGFjcm9zcyBsYXRpdHVkZXMuCgo8IS0tIGxhdGl0dWRpbmFsIGRpdmVyc2l0eSAtLT4KU3BpZGVycyBiaW9kaXZlcnNpdHkgaXMgZ2VuZXJhbGx5IGtub3duIHRvIGRlY3JlYXNlIHdpdGggZGlzdGFuY2UgZnJvbSB0aGUgZXF1YXRvciBbQFBsYXRuaWNrMTk5MTsgQFBpZWwyMDE4XS4gVG8gZXZhbHVhdGUgdGhlIGxhdGl0dWRpbmFsIGRpdmVyc2l0eSBncmFkaWVudCBvZiB0aGUgQk9MRCBzcGlkZXJzIGRhdGEsIEkgZmlyc3QgZ3JvdXBlZCByZWNvcmRzIGludG8gZm91ciAnbGF0aXR1ZGluYWwgY29tbXVuaXRpZXMnIGJhc2VkIG9uIGFic29sdXRlIGxhdGl0dWRlOiB0cm9waWNhbCAoKy8tMC0yMCBkZWcpLCBzdWItdHJvcGljYWwgKDIwLTQwKSwgdGVtcGVyYXRlICg0MC02MCkgYW5kIGV4dHJlbWUgKDYwKykuIFNpbWlsYXJseSwgc3BlY2ltZW4tc291cmNlIGNvdW50cmllcyB3ZXJlIGNhdGVnb3JpemVkIGludG8gdGhlc2Ugem9uZXMgYmFzZWQgb24gdGhlIG1lYW4gbGF0aXR1ZGUgb2Ygc3BlY2ltZW5zIGNvbGxlY3RlZCBpbiBlYWNoIGNvdW50cnkuIAoKPCEtLSByYXJlZmFjdGlvbiAtLT4KRGl2ZXJzaXR5IGFuYWx5c2VzIG9mIHRoZXNlIG5hdGlvbmFsIGFuZCBsYXRpdHVkaW5hbCBjb21tdW5pdGllcyBzaG93ZWQgdGhhdCBkaXZlcnNpdHkgZ2VuZXJhbGx5IGRlY3JlYXNlcyB3aXRoIGRpc3RhbmNlIGZyb20gdGhlIGVxdWF0b3IsIGFzIHdhcyBleHBlY3RlZCBmcm9tIHByZXZpb3VzIHJlc2VhcmNoIFtAUGxhdG5pY2sxOTkxOyBAUGllbDIwMThdLiBPdmVyYWxsLCB0aGUgc3ViLXRyb3BpY2FsIHpvbmUgY29udGFpbmVkIHRoZSBncmVhdGVzdCBiYXJjb2RlIChCSU4pIHJpY2huZXNzIGZvbGxvd2VkIGJ5IHRoZSB0ZW1wZXJhdGUgYW5kIHRyb3BpY2FsIHpvbmVzICh0YWJsZSAyLCBmaWcgMmIuKS4gUmFyZWZhY3Rpb24gYW5hbHlzaXMgc2hvd2VkIHRoYXQgdGhlIHN1Yi10cm9waWNhbCBhbmQgdHJvcGljYWwgY29tbXVuaXRpZXMgYXJlIGZhaXJseSBzaW1pbGFyIGluIHRlcm1zIG9mIGRpdmVyc2l0eSBhbmQgYXJlIG1vcmUgZGl2ZXJzZSB0aGFuIHRoZSB0ZW1wZXJhdGUgYW5kIGV4dHJlbWUgbGF0aXR1ZGUgem9uZXMgKGZpZy4gM2IpLiBXaGVuIG5hdGlvbmFsIGNvbW11bml0aWVzIGFyZSBjb25zaWRlcmVkLCB3ZSBjYW4gc2VlIHRoYXQgdGhlcmUgaXMgYSBsYXJnZSBkZWdyZWUgb2YgdmFyaWFuY2UgaW4gZGl2ZXJzaXR5IGJldHdlZW4gY291bnRyaWVzIGF0IHNpbWlsYXIgZGlzdGFuY2VzIGZyb20gdGhlIGVxdWF0b3IsIGFuZCB0aGlzIGlzIGVzcGVjaWFsbHkgdHJ1ZSBmb3IgdGhlIGNvbW11bml0aWVzIG9mIHRoZSBmZXcgdHJvcGljYWwgbmF0aW9ucyBleGFtaW5lZCAob25seSBmaWcuIDNjLGQpLgoKPCEtLSBhbHBoYSBkaXZlcnNpdHkgLS0+CldoZW4gY29uc2lkZXJpbmcgZXF1YWwgc2FtcGxlIHNpemVzLCB0aGUgc3ViLXRyb3BpY2FsIHpvbmUgaGFkIHRoZSBncmVhdGVzdCByYXJlZmllZCBCSU4gcmljaG5lc3MgYnV0IHRoaXMgd2FzIG9ubHkgc2xpZ2h0bHkgbGFyZ2VyIHRoYW4gdGhlIHRyb3BpY2FsIHpvbmUgKHRhYmxlIDIsIGZpZy4gNCkuIFRlbXBlcmF0ZSBhbmQgZXh0cmVtZSBsYXRpdHVkZXMgaGFkIHJlbGF0aXZlbHkgbG93IFNoYW5ub24gZGl2ZXJzaXR5LCB3aGlsZSB0aGUgc3VidHJvcGljYWwtem9uZSBoYWQgYSBzbGlnaHRseSBncmVhdGVyIFNoYW5ub24gZGl2ZXJzaXR5IHRoYW4gdGhlIHRyb3BpY2FsIHpvbmUuIFNpbXBzb24gZGl2ZXJzaXR5IHdhcyBub3QgdmVyeSBpbmZvcm1hdGl2ZSBmb3IgZGlmZmVyZW50aWF0aW5nIGNvbW11bml0aWVzIGF0IHRoZSB6b25lIG9yIGNvdW50cnkgbGV2ZWwsIHdpdGggbW9zdCB2YWx1ZXMgYXBwcm9hY2hpbmcgMS4gQW5vdmEgdGVzdHMgb2YgY291bnRyaWVzJyByaWNobmVzcyBhbmQgU2hhbm5vbiBpbmRleCBkYXRhIHNob3dlZCB0aGF0IHRoZSBkaWZmZXJlbmNlcyBpbiBtZWFucyBiZXR3ZWVuIGxhdGl0dWRlIHpvbmVzIHdlcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuIFRoaXMgYW5hbHlzaXMgd2FzIGhpbmRlcmVkIGJ5IHRoZSBsb3cgbnVtYmVyIG9mIHNpdGUgY291bnRyaWVzIGhhdmluZyBlbm91Z2ggc3BlY2ltZW5zIChuPjQ5OSwgY291bnRyaWVzPTIxKSBhbmQgdGhlc2Ugd2VyZSBjb25jZW50cmF0ZWQgaW4gdGhlIHRlbXBlcmF0ZSBhbmQgc3VidHJvcGljYWwgem9uZXMsIGxlYWRpbmcgdG8gbGFyZ2UgZXJyb3IgdmFsdWVzIGluIGVzdGltYXRpbmcgdGhlIGRpdmVyc2l0eSBvZiB0cm9waWNhbCBhbmQgZXh0cmVtZSB6b25lcy4gT3ZlcmFsbCwgdGhlIEJPTEQgc3BpZGVycyBkYXRhIGZvbGxvdyB0aGUgZXhwZWN0ZWQgbmVnYXRpdmUgbGF0aXR1ZGUtZGl2ZXJzaXR5IHRyZW5kOyBob3dldmVyLCBwZWFrIHJpY2huZXNzIGFuZCBkaXZlcnNpdHkgd2FzIG9ic2VydmVkIGluIHRoZSBzdWItdHJvcGljYWwgem9uZXMgKCsvLSAyMC00MCBkZWcgbGF0aXR1ZGUpLgoKCjwhLS0gTk1EUyArIE5FVFdPUksgLS0+Ck9yZGluYXRpb24gYW5kIG5ldHdvcmsgYW5hbHlzaXMgb2YgbGF0aXR1ZGUgem9uZSBjb21tdW5pdGllcyBzaG93ZWQgdGhhdCB0aGUgdGVtcGVyYXRlIGFuZCBleHRyZW1lIHpvbmVzIHdlcmUgdGhlIG1vc3Qgc2ltaWxhciBpbiBjb21wb3NpdGlvbiBhbmQgaGFkIHRoZSBncmVhdGVzdCBudW1iZXIgb2Ygc2hhcmVkIEJJTnMgYXQgNjU0IChmaWdzLiA1LDYpLCByZXByZXNlbnRpbmcgNzglIG9mIHRoZSBCSU5zIGZyb20gdGhlIGV4dHJlbWUgbGF0aXR1ZGUgY29tbXVuaXR5IGFuZCAyMiUgb2YgdGhlIHRlbXBlcmF0ZSBjb21tdW5pdHkuIFRoaXMgd2FzIGNvbnRyYXN0ZWQgYnkgdGhlIHJlbGF0aXZlbHkgZmV3IGJpbnMgc2hhcmVkIGJldHdlZW4gdGhlIHRyb3BpY2FsLCBzdWItdHJvcGljYWwsIGFuZCB0ZW1wZXJhdGUgem9uZXMuIEZyb20gb3JkaW5hdGlvbiwgd2Ugc2VlIHRoYXQgdGhlIGV4dHJlbWUgYW5kIHRlbXBlcmF0dXJlIGNvbW11bml0aWVzIGFyZSBtb3N0IHNpbWlsYXIgaW4gdGVybXMgb2YgY29tcG9zaXRpb24gd2hpbGUgdGhlIHN1Yi10cm9waWNhbCBhbmQgdHJvcGljYWwgem9uZXMgYXJlIGFzIGRpc3NpbWlsYXIgdG8gdGhlIHRlbXBlcmF0ZSBhbmQgZXh0cmVtZSB6b25lcyBhcyB0aGV5IGFyZSB0byBlYWNoIG90aGVyLgoKPCEtLSBUaGUgc2FtcGxpbmcgZWZmb3J0IGluIHNvbWUgY291bnRyaWVzIGlzIGVzcGVjaWFsbHkgc3VzcGVjdC4gIC0tPgoKVGhlIG1hcHBpbmcgb2Ygc3BlY2ltZW5zIGFuZCByYXJlZmFjdGlvbiBjdXJ2ZXMgcHJvZHVjZWQgZnJvbSBCSU4gYWJ1bmRhbmNlcyBieSBjb3VudHJ5IGFuZCBsYXRpdHVkZSB6b25lIChmaWcuIDIpIGJvdGggc2hvdyBhIHN0cm9uZyBnZW9ncmFwaGljIGJpYXMgaW4gdGhlIGRhdGFiYXNlIGFuZCBhbiB1bmRlci1wb3dlcmVkIHNhbXBsaW5nIG9mIG1hbnkgcmVnaW9ucywgcGFydGljdWxhcmx5IGF0IHRyb3BpY2FsIGxhdGl0dWRlcy4gRGVzcGl0ZSB0aGUgd2lkZSByYW5nZSBvZiBzb3VyY2UgY291bnRyaWVzLCBDYW5hZGlhbiBzcGVjaW1lbnMgYWNjb3VudCBmb3IgbmVhcmx5IGhhbGYgdGhlIGNvbGxlY3Rpb24gd2l0aCB0aGUgcmVtYWluaW5nIHJlY29yZHMgYmVpbmcgcHJlZG9taW5hbnRseSBmcm9tIHRoZSBVUyBhbmQgaGFuZGZ1bCBvZiBvdGhlciBjb3VudHJpZXMuIFRoaXMgJ0JvcmVhbCBiaWFzJyBpcyBhIHByZXZhbGVudCB0aGVtZSBpbiBlY29sb2d5IFtAUGxhdG5pY2sxOTkxXSBhbmQgdGhlIEJPTEQgZGF0YSByZWZsZWN0cyB0aGlzLiBBcyBzdWNoLCBzb21lIHJlc3VsdHMgb2YgdGhpcyBkaXZlcnNpdHkgYW5hbHlzaXMgYXJlIHBhcnRpY3VsYXJseSBzdXNwZWN0LiBCcmF6aWwsIGZvciBleGFtcGxlLCBhcHBlYXJzIHRvIGhhdmUgZXh0cmVtZWx5IGxvdyBzcGlkZXIgZGl2ZXJzaXR5IGJ1dCB0aGlzIGlzIGNvbnRyYXJ5IHRvIHdoYXQgaXMgZXhwZWN0ZWQgZnJvbSB0aGUgbGF0aXR1ZGUtZGl2ZXJzaXR5IHRyZW5kIGFuZCB0aGUgaGlnaGx5LXByb2R1Y3RpdmUgbGFuZHNjYXBlLgoKPCEtLSBjb25jbHVzaW9uIC0tPgpJbiBzdW1tYXJ5LCBCT0xEIGRhdGEgc2hvdyBkZWNyZWFzaW5nIHRyZW5kIGluIHNwaWRlciBiaW9kaXZlcnNpdHkgd2l0aCBkaXN0YW5jZSBmcm9tIHRoZSBlcXVhdG9yIGFzIGhhcyBiZWVuIHByZXZpb3VzbHkgZGVzY3JpYmVkIFtAUGllbDIwMTgsIEBQbGF0bmljazE5OTFdLiBUaGVyZSBpcyBncmVhdCB2YXJpYXRpb24gaW4gZGl2ZXJzaXR5IGJldHdlZW4gY291bnRyaWVzIGluIHRoZSBCT0xEIGRhdGEgYW5kIGEgbGltaXRlZCBudW1iZXIgb2YgdHJvcGljYWwgY291bnRyaWVzIHdpdGggYWRlcXVhdGUgc2FtcGxpbmcuIFRoaXMgbWFkZSBpdCBkaWZmaWN1bHQgZmluZCBzaWduaWZpY2FudCBjaGFuZ2VzIGluIHJpY2huZXNzIG9yIGRpdmVyc2l0eSBhY3Jvc3MgbGF0aXR1ZGVzLiBTYW1wbGluZyBiaWFzIGhhcyBhZmZlY3RlZCB0aGUgYW5hbHlzaXMgdG8gYW4gZXh0ZW50IGJ1dCB0aGlzIGlzIHNvbWV3aGF0IGNvbXBlbnNhdGVkIGZvciBieSB0aGUgbGFyZ2Ugdm9sdW1lIG9mIHNwZWNpbWVucyBjb2xsZWN0ZWQgYW5kIHRoZSB1c2Ugb2YgYnJvYWQgbGF0aXR1ZGUgem9uZXMuIFRoZSBCT0xEIGRhdGFiYXNlIGlzIGluZGVlZCBhIHZhbHVhYmxlIHJlc291cmNlIGZvciBldmFsdWF0aW5nIGdsb2JhbCBlY29sb2dpY2FsIHRyZW5kcy4gQk9MRCdzIHZhbHVlIHdpbGwgY29udGludWUgdG8gaW5jcmVhc2Ugd2l0aCB0aGUgYWRkaXRpb24gb2YgY29sbGVjdGlvbnMgZnJvbSB1bmRlci1yZXByZXNlbnRlZCBhcmVhcy4KCgojIENvZGUgYW5kIHN1cHBsZW1lbnRhbAoKUGxlYXNlIGZpbmQgdGhlIGNvZGUgdXNlZCB0byBjcmVhdGUgdGhpcyB3b3JrIGluIHRoZSBmaWxlIGBKTW9nZ19zcGlkZXJfZGl2ZXJzaXR5X25vdGVib29rLm5iLmh0bWxgIHdoZXJlIGl0IGlzIHByZXNlbnRlZCBpbiB0aGUgJ2xpdGVyYXRlIHByb2dyYW1taW5nJyBzdHlsZS4gVGhpcyBwZGYgZG9jdW1lbnQgYW5kIHRoZSBub3RlYm9vayB3ZXJlIHJlbmRlcmVkIGZyb20gUm1hcmtkb3duIGZpbGVzIGBKTW9nZ19zcGlkZXJfZGl2ZXJzaXR5X3BkZi5SbWRgIGFuZCBgSk1vZ2dfc3BpZGVyX2RpdmVyc2l0eV9ub3RlYm9vay5SbWRgLCByZXNwZWN0aXZlbHkuIEZpZ3VyZXMgaGF2ZSBiZWVuIGxhYmVsbGVkIGluIHRoZSBvcmRlciB0aGF0IHRoZXkgYXBwZWFyIGluIHRoZSBwZGYgZm9ybWF0LgoKLS0tLS0KCiMgQWNrbm93bGVkZ2VtZW50cwoKV2UgdHJ1bHkgc3RhbmQgb24gdGhlIHNob3VsZGVycyBvZiBnaWFudHMgYW5kIEkgZm91bmQgdGhlIGZvbGxvd2luZyB0dXRvcmlhbHMgdmVyeSBoZWxwZnVsIHdoaWxlIGNyZWF0aW5nIHRoaXMgd29yazoKCi0gVmVnYW4gVHV0b3JpYWwgYnkgUGV0ZXIgQ2xhcmsgaHR0cHM6Ly9wZWF0LWNsYXJrLmdpdGh1Yi5pby9CSU8zODEvdmVnYW5UdXRvcmlhbC5odG1sIAoKLSBNb3NxdWl0byBjb21tdW5pdHkgZGl2ZXJzaXR5IGFuYWx5c2lzIHdpdGggdmVnYW4gYnkgUmFuZGkgSCBHcmlmZmluIGh0dHA6Ly93d3cucmFuZGlncmlmZmluLmNvbS8yMDE3LzA1LzIzL21vc3F1aXRvLWNvbW11bml0eS1lY29sb2d5LWluLXZlZ2FuLmh0bWwKCi0gTmV0d29yayBBbmFseXNpcyBhbmQgVmlzdWFsaXphdGlvbiB3aXRoIFIgYW5kIGlncmFwaCBieQpLYXRoZXJpbmUgT2dueWFub3ZhIGh0dHBzOi8va2F0ZXRvLm5ldC9uZXRzY2l4MjAxNi5odG1sCgotLS0tLQoKIyBSZWZlcmVuY2VzCgo8IS0tIGJpYmxpb2dyYXBoeSBmcm9tIHJlZmVyZW5jZXMuYmliIGlzIGluc2VydGVkIGF0IGVuZCBvZiBwZGYgd2hlbiBrbml0dGluZyAtLT4KCgoKCjwhLS0gYGBge3J9IC0tPgo8IS0tIGF0dGFjaChhbHBoYS5kaXZlcnNpdHkuY291bnRyeSkgLS0+CjwhLS0gbW9kZWwxIDwtIGxtKFJhcmVmaWVkIH4gem9uZSkgLS0+CjwhLS0gc3VtbWFyeShtb2RlbDEpIC0tPgo8IS0tIGFub3ZhKG1vZGVsMSkgLS0+CjwhLS0gcGxvdChSYXJlZmllZH5ab25lKSAtLT4KCjwhLS0gbW9kZWwyIDwtIGxtKFNoYW5ub24gfiB6b25lKSAtLT4KPCEtLSBzdW1tYXJ5KG1vZGVsMikgLS0+CjwhLS0gYW5vdmEobW9kZWwyKSAtLT4KPCEtLSBwbG90KFNoYW5ub25+em9uZSkgLS0+CjwhLS0gYGBgIC0tPgo=